自己编写的一个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了。

 代码:  

 

 

  1. package com.aherp.framework.util;
  2. import org.json.JSONString;
  3. public class JSONStringObject implements JSONString {
  4.     private String jsonString = null;
  5.     
  6.     public JSONStringObject(String jsonString){
  7.         this.jsonString = jsonString;
  8.     }
  9.     @Override
  10.     public String toString() {
  11.         return jsonString;
  12.     }
  13.     public String toJSONString() {
  14.         return jsonString;
  15.     }
  16. }

 

 

  1. package com.aherp.framework.util;
  2. import java.lang.reflect.Array;
  3. import java.lang.reflect.Method;
  4. import java.util.Calendar;
  5. import java.util.Date;
  6. import java.util.Map;
  7. import java.util.Map.Entry;
  8. import org.json.JSONArray;
  9. import org.json.JSONException;
  10. import org.json.JSONObject;
  11. import org.json.JSONString;
  12. /**
  13.  * JSON工具类,反射的方式转换整个对象
  14.  * @author Jim Wu
  15.  *
  16.  */
  17. public class JSONUtil {
  18.     private static JSONUtil instance = null;
  19.     
  20.     public JSONUtil(){}
  21.     
  22.     /**
  23.      * 代理类是否输出的检查,返回true则允许继续转换
  24.      * @param bean
  25.      * @return 是否允许继续转换
  26.      */
  27.     protected boolean canProxyOutput(Object bean) {
  28.         return true;
  29.     }
  30.     /**
  31.      * 代理类时做的检查.返回应该检查的对象.
  32.      * @param bean
  33.      * @return 实际获取的对象 
  34.      */
  35.     protected Object proxyConvert(Object bean){
  36.         return bean;
  37.     }
  38.     static public String toJSONString(Object obj) throws JSONException{
  39.         return toJSONString(obj, false);
  40.     }
  41.     
  42.     static public String toJSONString(Object obj, boolean useClassConvert) throws JSONException{
  43.         if(instance == null)
  44.             instance = new JSONUtil();
  45.         return instance.getJSONObject(obj, useClassConvert).toString();
  46.     }
  47.     @SuppressWarnings("unchecked")
  48.     private String getJSONArray(Object arrayObj, boolean useClassConvert) throws JSONException{
  49.         
  50.         if(arrayObj == null)
  51.             return "null";
  52.         
  53.         arrayObj = proxyConvert(arrayObj);
  54.         
  55.         JSONArray jSONArray = new JSONArray();
  56.         if(arrayObj instanceof Iterable){
  57.             for(Object rowObj: ((Iterable)arrayObj)){
  58.                 if(canProxyOutput(rowObj)){
  59.                     if(rowObj == null)
  60.                         jSONArray.put(new JSONStringObject(null));
  61.                     else if(rowObj.getClass().isArray() || rowObj instanceof Iterable)
  62.                         jSONArray.put(getJSONArray(rowObj, useClassConvert));
  63.                     else
  64.                         jSONArray.put(getJSONObject(rowObj, useClassConvert));
  65.                 }
  66.             }
  67.         }
  68.         if(arrayObj.getClass().isArray()){
  69.             int arrayLength = Array.getLength(arrayObj);
  70.             for(int i = 0; i < arrayLength; i ++){
  71.                 Object rowObj = Array.get(arrayObj, i);
  72.                 if(canProxyOutput(rowObj)){
  73.                     if(rowObj == null)
  74.                         jSONArray.put(new JSONStringObject(null));
  75.                     else if(rowObj.getClass().isArray() || rowObj instanceof Iterable)
  76.                         jSONArray.put(getJSONArray(rowObj, useClassConvert));
  77.                     else
  78.                         jSONArray.put(getJSONObject(rowObj, useClassConvert));
  79.                 }
  80.             }
  81.         }
  82.         return jSONArray.toString();
  83.     }
  84.     @SuppressWarnings("unchecked")
  85.     JSONStringObject getJSONObject(Object value, boolean useClassConvert) throws JSONException{
  86.         //处理原始类型
  87.         if (value == null) {
  88.             return new JSONStringObject("null");
  89.         }
  90.         value = proxyConvert(value);
  91.         if (value instanceof JSONString) {
  92.             Object o;
  93.             try {
  94.                 o = ((JSONString)value).toJSONString();
  95.             } catch (Exception e) {
  96.                 throw new JSONException(e);
  97.             }
  98.             throw new JSONException("Bad value from toJSONString: " + o);
  99.         }
  100.         if (value instanceof Number) {
  101.             return new JSONStringObject(JSONObject.numberToString((Number) value));
  102.         }
  103.         if (value instanceof Boolean || value instanceof JSONObject ||
  104.                 value instanceof JSONArray) {
  105.             return new JSONStringObject(value.toString());
  106.         }
  107.         if (value instanceof String)
  108.             return new JSONStringObject('"' + JavascriptUtil.escapeJavaScript(value.toString()) + '"');
  109.         if (value instanceof Map) {
  110.             
  111.             JSONObject jSONObject = new JSONObject();
  112.             for(Object rowObj: ((Map)value).entrySet()){
  113.                 Entry entry = (Entry)rowObj;
  114.                 Object valueObj = entry.getValue();
  115.                 if(canProxyOutput(valueObj))
  116.                     jSONObject.put(entry.getKey().toString(), getJSONObject(valueObj, useClassConvert));
  117.             }
  118.             return new JSONStringObject(jSONObject.toString());
  119.         }
  120.         if(value instanceof Date){
  121.             Calendar calendar = Calendar.getInstance();
  122.             calendar.setTime(calendar.getTime());
  123.             StringBuilder sb = new StringBuilder("new Date(");
  124.             sb.append(calendar.get(Calendar.YEAR));
  125.             sb.append(",");
  126.             sb.append(calendar.get(Calendar.MONTH));
  127.             sb.append(",");
  128.             sb.append(calendar.get(Calendar.DAY_OF_MONTH));
  129.             sb.append(",");
  130.             sb.append(calendar.get(Calendar.HOUR_OF_DAY));
  131.             sb.append(",");
  132.             sb.append(calendar.get(Calendar.MINUTE));
  133.             sb.append(",");
  134.             sb.append(calendar.get(Calendar.SECOND));
  135.             sb.append(")");
  136.             return new JSONStringObject(sb.toString());
  137.         }
  138.         //class
  139.         if(value instanceof Class)
  140.             return new JSONStringObject(JavascriptUtil.escapeJavaScript(((Class)value).getSimpleName()));
  141.         
  142.         //数组
  143.         if (value instanceof Iterable || value.getClass().isArray()) {
  144.             return new JSONStringObject(getJSONArray(proxyConvert(value), useClassConvert));
  145.         }
  146.         return reflectObject(value, useClassConvert);
  147.     }
  148.     @SuppressWarnings("unchecked")
  149.     private JSONStringObject reflectObject(Object bean, boolean useClassConvert){
  150.         JSONObject jSONObject = new JSONObject();
  151.         Class klass = bean.getClass();
  152.         for (Method method: klass.getMethods()) {
  153.             try {
  154.                 String name = method.getName();
  155.                 String key = "";
  156.                 if (name.startsWith("get")) {
  157.                     key = name.substring(3);
  158.                 } else if (name.startsWith("is")) {
  159.                     key = name.substring(2);
  160.                 }
  161.                 if (key.length() > 0 &
  162.                         Character.isUpperCase(key.charAt(0)) &
  163.                         method.getParameterTypes().length == 0) {
  164.                     if (key.length() == 1) {
  165.                         key = key.toLowerCase();
  166.                     } else if (!Character.isUpperCase(key.charAt(1))) {
  167.                         key = key.substring(01).toLowerCase() +
  168.                             key.substring(1);
  169.                     }
  170.                     Object elementObj = method.invoke(bean);
  171.                     if(!useClassConvert && elementObj instanceof Class)
  172.                         continue;
  173.                     if(canProxyOutput(elementObj))
  174.                         jSONObject.put(key, getJSONObject(elementObj, useClassConvert));
  175.                 }
  176.             } catch (Exception e) {
  177.                 /* forget about it */
  178.             }
  179.         }
  180.         return new JSONStringObject(jSONObject.toString());
  181.     }
  182. }

调用测试程序

import  java.util.ArrayList;
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.math.BigDecimal;
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[]{352false"kick"};

    
public Object[] getOarray() {
        
return oarray;
    }


    
public void setOarray(Object[] oarray) {
        
this.oarray = oarray;
    }

}

 

import  org.json.JSONException;

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如下:

 


 

  1. package com.aherp.framework.util;
  2. import org.hibernate.collection.PersistentSet;
  3. import org.hibernate.proxy.HibernateProxy;
  4. import org.hibernate.proxy.LazyInitializer;
  5. import org.json.JSONException;
  6. /**
  7.  * 支持Hibernate的JSONUtil.
  8.  * 自动检测是否已经代理加载,如果未加载,则将对象仅加载为OID
  9.  * @author Jim Wu
  10.  *
  11.  */
  12. public class HiJSONUtil extends JSONUtil {
  13.     private static HiJSONUtil instance = null;
  14.     static public String toJSONString(Object obj) throws JSONException{
  15.         return toJSONString(obj, false);
  16.     }
  17.     
  18.     static public String toJSONString(Object obj, boolean useClassConvert) throws JSONException{
  19.         if(instance == null)
  20.             instance = new HiJSONUtil();
  21.         return instance.getJSONObject(obj, useClassConvert).toString();
  22.     }
  23.     @Override
  24.     protected Object proxyConvert(Object bean) {
  25.         if(bean instanceof HibernateProxy){
  26.             LazyInitializer lazyInitializer = ((HibernateProxy)bean).getHibernateLazyInitializer();
  27.             if(lazyInitializer.isUninitialized()){
  28.                 return lazyInitializer.getIdentifier();
  29.             }else
  30.                 return lazyInitializer.getImplementation();
  31.         }
  32.         if(bean instanceof PersistentSet || bean instanceof PersistentList){
  33.             return new String[]{}; //忽略hibernate one-to-many
  34.         }
  35.         return bean;
  36.     }
  37.     @Override
  38.     protected boolean canProxyOutput(Object bean) {
  39.         return !(bean != null && (bean instanceof PersistentSet || bean instanceof PersistentList));
  40.     }
  41. }
  42. ;

但是这样还是有个问题,当one-to-one具备双向映射关系时,会陷入调用递归死循环。因此避免这样的情况。

将本人修改过的JavaScriptUtil也附上

  1. /*
  2.  * Copyright 2005 Joe Walker
  3.  *
  4.  * Licensed under the Apache License, Version 2.0 (the "License");
  5.  * you may not use this file except in compliance with the License.
  6.  * You may obtain a copy of the License at
  7.  *
  8.  *     http://www.apache.org/licenses/LICENSE-2.0
  9.  *
  10.  * Unless required by applicable law or agreed to in writing, software
  11.  * distributed under the License is distributed on an "AS IS" BASIS,
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13.  * See the License for the specific language governing permissions and
  14.  * limitations under the License.
  15.  */
  16. package com.aherp.framework.util;
  17. import java.io.BufferedReader;
  18. import java.io.IOException;
  19. import java.io.StringReader;
  20. import java.util.Arrays;
  21. import java.util.Locale;
  22. import java.util.SortedSet;
  23. import java.util.TreeSet;
  24. import org.apache.commons.logging.Log;
  25. import org.apache.commons.logging.LogFactory;
  26. /**
  27.  * Various Javascript code utilities.
  28.  * The escape classes were taken from jakarta-commons-lang which in turn borrowed
  29.  * from Turbine and other projects. The list of authors below is almost certainly
  30.  * far too long, but I'm not sure who really wrote these methods.
  31.  * @author Joe Walker [joe at getahead dot ltd dot uk]
  32.  * @author Apache Jakarta Turbine
  33.  * @author GenerationJavaCore library
  34.  * @author Purple Technology
  35.  * @author <a href="mailto:bayard@generationjava.com">Henri Yandell</a>
  36.  * @author <a href="mailto:alex@purpletech.com">Alexander Day Chaffee</a>
  37.  * @author <a href="mailto:cybertiger@cyberiantiger.org">Antony Riley</a>
  38.  * @author Helge Tesgaard
  39.  * @author <a href="sean@boohai.com">Sean Brown</a>
  40.  * @author <a href="mailto:ggregory@seagullsw.com">Gary Gregory</a>
  41.  * @author Phil Steitz
  42.  * @author Pete Gieser
  43.  */
  44. @SuppressWarnings("unchecked")
  45. public class JavascriptUtil
  46. {
  47.     /**
  48.      * Flag for use in javascript compression: Remove single line comments.
  49.      * For ease of use you may wish to use one of the LEVEL_* compression levels.
  50.      * @noinspection PointlessBitwiseExpression
  51.      */
  52.     public static final int COMPRESS_STRIP_SL_COMMENTS = 1 << 0;
  53.     /**
  54.      * Flag for use in javascript compression: Remove multi line comments.
  55.      * For ease of use you may wish to use one of the LEVEL_* compression levels.
  56.      */
  57.     public static final int COMPRESS_STRIP_ML_COMMENTS = 1 << 1;
  58.     /**
  59.      * Flag for use in javascript compression: Remove whitespace at the start and end of a line.
  60.      * For ease of use you may wish to use one of the LEVEL_* compression levels.
  61.      */
  62.     public static final int COMPRESS_TRIM_LINES = 1 << 2;
  63.     /**
  64.      * Flag for use in javascript compression: Remove blank lines.
  65.      * This option will make the javascript harder to debug because line number references
  66.      * are likely be altered.
  67.      * For ease of use you may wish to use one of the LEVEL_* compression levels.
  68.      */
  69.     public static final int COMPRESS_STRIP_BLANKLINES = 1 << 3;
  70.     /**
  71.      * Flag for use in javascript compression: Shrink variable names.
  72.      * This option is currently un-implemented.
  73.      * For ease of use you may wish to use one of the LEVEL_* compression levels.
  74.      */
  75.     public static final int COMPRESS_SHRINK_VARS = 1 << 4;
  76.     /**
  77.      * Flag for use in javascript compression: Remove all lines endings.
  78.      * Warning: Javascript can add semi-colons in for you. If you make use of this feature
  79.      * then removing newlines may well break.
  80.      * For ease of use you may wish to use one of the LEVEL_* compression levels.
  81.      */
  82.     public static final int COMPRESS_REMOVE_NEWLINES = 1 << 5;
  83.     /**
  84.      * Compression level that leaves the source un-touched.
  85.      */
  86.     public static final int LEVEL_NONE = 0;
  87.     /**
  88.      * Basic compression that leaves the source fully debuggable.
  89.      * This includes removing all comments and extraneous whitespace.
  90.      */
  91.     public static final int LEVEL_DEBUGGABLE = COMPRESS_STRIP_SL_COMMENTS | COMPRESS_STRIP_ML_COMMENTS | COMPRESS_TRIM_LINES;
  92.     /**
  93.      * Normal compression makes all changes that will work for generic javascript.
  94.      * This adds variable name compression and blank line removal in addition to the
  95.      * compressions done by LEVEL_DEBUGGABLE.
  96.      */
  97.     public static final int LEVEL_NORMAL = LEVEL_DEBUGGABLE | COMPRESS_STRIP_BLANKLINES | COMPRESS_SHRINK_VARS;
  98.     /**
  99.      * LEVEL_ULTRA performs additional compression that makes some assumptions about the
  100.      * style of javascript.
  101.      * Specifically it assumes that you are not using javascripts ability to infer where the ;
  102.      * should go.
  103.      */
  104.     public static final int LEVEL_ULTRA = LEVEL_NORMAL | COMPRESS_REMOVE_NEWLINES;
  105.     /**
  106.      * Compress the source code by removing java style comments and removing
  107.      * leading and trailing spaces.
  108.      * @param text The javascript (or java) program to compress
  109.      * @param level The compression level - see LEVEL_* and COMPRESS_* constants.
  110.      * @return The compressed version
  111.      */
  112.     public static String compress(String text, int level)
  113.     {
  114.         String reply = text;
  115.         // First we strip multi line comments. I think this is important:
  116.         if ((level & COMPRESS_STRIP_ML_COMMENTS) != 0)
  117.         {
  118.             reply = stripMultiLineComments(text);
  119.         }
  120.         if ((level & COMPRESS_STRIP_SL_COMMENTS) != 0)
  121.         {
  122.             reply = stripSingleLineComments(reply);
  123.         }
  124.         if ((level & COMPRESS_TRIM_LINES) != 0)
  125.         {
  126.             reply = trimLines(reply);
  127.         }
  128.         if ((level & COMPRESS_STRIP_BLANKLINES) != 0)
  129.         {
  130.             reply = stripBlankLines(reply);
  131.         }
  132.         if ((level & COMPRESS_SHRINK_VARS) != 0)
  133.         {
  134.             reply = shrinkVariableNames(reply);
  135.         }
  136.         if ((level & COMPRESS_REMOVE_NEWLINES) != 0)
  137.         {
  138.             reply = stripNewlines(reply);
  139.         }
  140.         return reply;
  141.     }
  142.     /**
  143.      * Remove any leading or trailing spaces from a line of code.
  144.      * This function could be improved by making it strip unnecessary double
  145.      * spaces, but since we would need to leave double spaces inside strings
  146.      * this is not simple and since the benefit is small, we'll leave it for now
  147.      * @param text The javascript program to strip spaces from.
  148.      * @return The stripped program
  149.      */
  150.     public static String trimLines(String text)
  151.     {
  152.         if (text == null)
  153.         {
  154.             return null;
  155.         }
  156.         try
  157.         {
  158.             StringBuffer output = new StringBuffer();
  159.             // First we strip multi line comments. I think this is important:
  160.             BufferedReader in = new BufferedReader(new StringReader(text));
  161.             while (true)
  162.             {
  163.                 String line = in.readLine();
  164.                 if (line == null)
  165.                 {
  166.                     break;
  167.                 }
  168.                 output.append(line.trim());
  169.                 output.append('/n');
  170.             }
  171.             return output.toString();
  172.         }
  173.         catch (IOException ex)
  174.         {
  175.             log.error("IOExecption unexpected.", ex);
  176.             throw new IllegalArgumentException("IOExecption unexpected.");
  177.         }
  178.     }
  179.     /**
  180.      * Remove all the single-line comments from a block of text
  181.      * @param text The text to remove single-line comments from
  182.      * @return The single-line comment free text
  183.      */
  184.     public static String stripSingleLineComments(String text)
  185.     {
  186.         if (text == null)
  187.         {
  188.             return null;
  189.         }
  190.         try
  191.         {
  192.             StringBuffer output = new StringBuffer();
  193.             BufferedReader in = new BufferedReader(new StringReader(text));
  194.             while (true)
  195.             {
  196.                 String line = in.readLine();
  197.                 if (line == null)
  198.                 {
  199.                     break;
  200.                 }
  201.                 // Skip @DWR comments
  202.                 if (line.indexOf(COMMENT_RETAIN) == -1)
  203.                 {
  204.                     int cstart = line.indexOf(COMMENT_SL_START);
  205.                     if (cstart >= 0)
  206.                     {
  207.                         line = line.substring(0, cstart);
  208.                     }
  209.                 }
  210.                 output.append(line);
  211.                 output.append('/n');
  212.             }
  213.             return output.toString();
  214.         }
  215.         catch (IOException ex)
  216.         {
  217.             log.error("IOExecption unexpected.", ex);
  218.             throw new IllegalArgumentException("IOExecption unexpected.");
  219.         }
  220.     }
  221.     /**
  222.      * Remove all the multi-line comments from a block of text
  223.      * @param text The text to remove multi-line comments from
  224.      * @return The multi-line comment free text
  225.      */
  226.     public static String stripMultiLineComments(String text)
  227.     {
  228.         if (text == null)
  229.         {
  230.             return null;
  231.         }
  232.         try
  233.         {
  234.             StringBuffer output = new StringBuffer();
  235.             // Comment rules:
  236.             /*/           This is still a comment
  237.             /* /* */      // Comments do not nest
  238.             // /* */      This is in a comment
  239.             /* // */      // The second // is needed to make this a comment.
  240.             // First we strip multi line comments. I think this is important:
  241.             boolean inMultiLine = false;
  242.             BufferedReader in = new BufferedReader(new StringReader(text));
  243.             while (true)
  244.             {
  245.                 String line = in.readLine();
  246.                 if (line == null)
  247.                 {
  248.                     break;
  249.                 }
  250.                 if (!inMultiLine)
  251.                 {
  252.                     // We are not in a multi-line comment, check for a start
  253.                     int cstart = line.indexOf(COMMENT_ML_START);
  254.                     if (cstart >= 0)
  255.                     {
  256.                         // This could be a MLC on one line ...
  257.                         int cend = line.indexOf(COMMENT_ML_END, cstart + COMMENT_ML_START.length());
  258.                         if (cend >= 0)
  259.                         {
  260.                             // A comment that starts and ends on one line
  261.                             // BUG: you can have more than 1 multi-line comment on a line
  262.                             line = line.substring(0, cstart) + SPACE + line.substring(cend + COMMENT_ML_END.length());
  263.                         }
  264.                         else
  265.                         {
  266.                             // A real multi-line comment
  267.                             inMultiLine = true;
  268.                             line = line.substring(0, cstart) + SPACE;
  269.                         }
  270.                     }
  271.                     else
  272.                     {
  273.                         // We are not in a multi line comment and we havn't
  274.                         // started one so we are going to ignore closing
  275.                         // comments even if they exist.
  276.                     }
  277.                 }
  278.                 else
  279.                 {
  280.                     // We are in a multi-line comment, check for the end
  281.                     int cend = line.indexOf(COMMENT_ML_END);
  282.                     if (cend >= 0)
  283.                     {
  284.                         // End of comment
  285.                         line = line.substring(cend + COMMENT_ML_END.length());
  286.                         inMultiLine = false;
  287.                     }
  288.                     else
  289.                     {
  290.                         // The comment continues
  291.                         line = SPACE;
  292.                     }
  293.                 }
  294.                 output.append(line);
  295.                 output.append('/n');
  296.             }
  297.             return output.toString();
  298.         }
  299.         catch (IOException ex)
  300.         {
  301.             log.error("IOExecption unexpected.", ex);
  302.             throw new IllegalArgumentException("IOExecption unexpected.");
  303.         }
  304.     }
  305.     /**
  306.      * Remove all blank lines from a string.
  307.      * A blank line is defined to be a line where the only characters are whitespace.
  308.      * We always ensure that the line contains a newline at the end.
  309.      * @param text The string to strip blank lines from
  310.      * @return The blank line stripped reply
  311.      */
  312.     public static String stripBlankLines(String text)
  313.     {
  314.         if (text == null)
  315.         {
  316.             return null;
  317.         }
  318.         try
  319.         {
  320.             StringBuffer output = new StringBuffer();
  321.             BufferedReader in = new BufferedReader(new StringReader(text));
  322.             boolean doneOneLine = false;
  323.             while (true)
  324.             {
  325.                 String line = in.readLine();
  326.                 if (line == null)
  327.                 {
  328.                     break;
  329.                 }
  330.                 if (line.trim().length() > 0)
  331.                 {
  332.                     output.append(line);
  333.                     output.append('/n');
  334.                     doneOneLine = true;
  335.                 }
  336.             }
  337.             if (!doneOneLine)
  338.             {
  339.                 output.append('/n');
  340.             }
  341.             return output.toString();
  342.         }
  343.         catch (IOException ex)
  344.         {
  345.             log.error("IOExecption unexpected.", ex);
  346.             throw new IllegalArgumentException("IOExecption unexpected.");
  347.         }
  348.     }
  349.     /**
  350.      * Remove all newline characters from a string.
  351.      * @param text The string to strip newline characters from
  352.      * @return The stripped reply
  353.      */
  354.     public static String stripNewlines(String text)
  355.     {
  356.         if (text == null)
  357.         {
  358.             return null;
  359.         }
  360.         try
  361.         {
  362.             StringBuffer output = new StringBuffer();
  363.             BufferedReader in = new BufferedReader(new StringReader(text));
  364.             while (true)
  365.             {
  366.                 String line = in.readLine();
  367.                 if (line == null)
  368.                 {
  369.                     break;
  370.                 }
  371.                 output.append(line);
  372.                 output.append(SPACE);
  373.             }
  374.             output.append('/n');
  375.             return output.toString();
  376.         }
  377.         catch (IOException ex)
  378.         {
  379.             log.error("IOExecption unexpected.", ex);
  380.             throw new IllegalArgumentException("IOExecption unexpected.");
  381.         }
  382.     }
  383.     /**
  384.      * Shrink variable names to a minimum.
  385.      * @param text The javascript program to shrink the variable names in.
  386.      * @return The shrunk version of the javascript program.
  387.      */
  388.     public static String shrinkVariableNames(String text)
  389.     {
  390.         if (text == null)
  391.         {
  392.             return null;
  393.         }
  394.         throw new UnsupportedOperationException("Variable name shrinking is not supported");
  395.     }
  396.     /**
  397.      * <p>Escapes the characters in a <code>String</code> using JavaScript String rules.</p>
  398.      * <p>Escapes any values it finds into their JavaScript String form.
  399.      * Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.) </p>
  400.      *
  401.      * <p>So a tab becomes the characters <code>'//'</code> and
  402.      * <code>'t'</code>.</p>
  403.      *
  404.      * <p>The only difference between Java strings and JavaScript strings
  405.      * is that in JavaScript, a single quote must be escaped.</p>
  406.      *
  407.      * <p>Example:
  408.      * <pre>
  409.      * input string: He didn't say, "Stop!"
  410.      * output string: He didn/'t say, /"Stop!/"
  411.      * </pre>
  412.      * </p>
  413.      *
  414.      * @param str  String to escape values in, may be null
  415.      * @return String with escaped values, <code>null</code> if null string input
  416.      */
  417.     public static String escapeJavaScript(String str)
  418.     {
  419.         if (str == null)
  420.         {
  421.             return null;
  422.         }
  423.         StringBuffer writer = new StringBuffer(str.length() * 2);
  424.         int sz = str.length();
  425.         for (int i = 0; i < sz; i++)
  426.         {
  427.             char ch = str.charAt(i);
  428.             // handle unicode
  429.             if (ch > 0xfff)
  430.             {
  431.                 writer.append("//u");
  432.                 writer.append(hex(ch));
  433.             }
  434.             else if (ch > 0xff)
  435.             {
  436.                 writer.append("//u0");
  437.                 writer.append(hex(ch));
  438.             }
  439.             else if (ch > 0x7f)
  440.             {
  441.                 writer.append("//u00");
  442.                 writer.append(hex(ch));
  443.             }
  444.             else if (ch < 32)
  445.             {
  446.                 switch (ch)
  447.                 {
  448.                 case '/b':
  449.                     writer.append('//');
  450.                     writer.append('b');
  451.                     break;
  452.                 case '/n':
  453.                     writer.append('//');
  454.                     writer.append('n');
  455.                     break;
  456.                 case '/t':
  457.                     writer.append('//');
  458.                     writer.append('t');
  459.                     break;
  460.                 case '/f':
  461.                     writer.append('//');
  462.                     writer.append('f');
  463.                     break;
  464.                 case '/r':
  465.                     writer.append('//');
  466.                     writer.append('r');
  467.                     break;
  468.                 default:
  469.                     if (ch > 0xf)
  470.                     {
  471.                         writer.append("//u00");
  472.                         writer.append(hex(ch));
  473.                     }
  474.                     else
  475.                     {
  476.                         writer.append("//u000");
  477.                         writer.append(hex(ch));
  478.                     }
  479.                     break;
  480.                 }
  481.             }
  482.             else
  483.             {
  484.                 switch (ch)
  485.                 {
  486.                 case '/'':
  487.                     // If we wanted to escape for Java strings then we would
  488.                     // not need this next line.
  489.                     writer.append('//');
  490.                     writer.append('/'');
  491.                     break;
  492.                 case '"':
  493.                     writer.append('//');
  494.                     writer.append('"');
  495.                     break;
  496.                 case '//':
  497.                     writer.append('//');
  498.                     writer.append('//');
  499.                     break;
  500.                 case '<':
  501.                     writer.append("//u003c");
  502.                     break;
  503.                 case '>':
  504.                     writer.append("//u003e");
  505.                     break;
  506.                 default:
  507.                     writer.append(ch);
  508.                     break;
  509.                 }
  510.             }
  511.         }
  512.         return writer.toString();
  513.     }
  514.     /**
  515.      * <p>Returns an upper case hexadecimal <code>String</code> for the given
  516.      * character.</p>
  517.      * @param ch The character to convert.
  518.      * @return An upper case hexadecimal <code>String</code>
  519.      */
  520.     private static String hex(char ch)
  521.     {
  522.         return Integer.toHexString(ch).toUpperCase(Locale.ENGLISH);
  523.     }
  524.     /**
  525.      * <p>Unescapes any JavaScript literals found in the <code>String</code>.</p>
  526.      * <p>For example, it will turn a sequence of <code>'/'</code> and <code>'n'</code>
  527.      * into a newline character, unless the <code>'/'</code> is preceded by another
  528.      * <code>'/'</code>.</p>
  529.      * @param str  the <code>String</code> to unescape, may be null
  530.      * @return A new unescaped <code>String</code>, <code>null</code> if null string input
  531.      */
  532.     public static String unescapeJavaScript(String str)
  533.     {
  534.         if (str == null)
  535.         {
  536.             return null;
  537.         }
  538.         StringBuffer writer = new StringBuffer(str.length());
  539.         int sz = str.length();
  540.         StringBuffer unicode = new StringBuffer(4);
  541.         boolean hadSlash = false;
  542.         boolean inUnicode = false;
  543.         for (int i = 0; i < sz; i++)
  544.         {
  545.             char ch = str.charAt(i);
  546.             if (inUnicode)
  547.             {
  548.                 // if in unicode, then we're reading unicode
  549.                 // values in somehow
  550.                 unicode.append(ch);
  551.                 if (unicode.length() == 4)
  552.                 {
  553.                     // unicode now contains the four hex digits
  554.                     // which represents our unicode chacater
  555.                     try
  556.                     {
  557.                         int value = Integer.parseInt(unicode.toString(), 16);
  558.                         writer.append((char) value);
  559.                         unicode.setLength(0);
  560.                         inUnicode = false;
  561.                         hadSlash = false;
  562.                     }
  563.                     catch (NumberFormatException nfe)
  564.                     {
  565.                         throw new IllegalArgumentException("Unable to parse unicode value: " + unicode + " cause: " + nfe);
  566.                     }
  567.                 }
  568.                 continue;
  569.             }
  570.             if (hadSlash)
  571.             {
  572.                 // handle an escaped value
  573.                 hadSlash = false;
  574.                 switch (ch)
  575.                 {
  576.                 case '//':
  577.                     writer.append('//');
  578.                     break;
  579.                 case '/'':
  580.                     writer.append('/'');
  581.                     break;
  582.                 case '/"':
  583.                     writer.append('"');
  584.                     break;
  585.                 case 'r':
  586.                     writer.append('/r');
  587.                     break;
  588.                 case 'f':
  589.                     writer.append('/f');
  590.                     break;
  591.                 case 't':
  592.                     writer.append('/t');
  593.                     break;
  594.                 case 'n':
  595.                     writer.append('/n');
  596.                     break;
  597.                 case 'b':
  598.                     writer.append('/b');
  599.                     break;
  600.                 case 'u':
  601.                     // uh-oh, we're in unicode country....
  602.                     inUnicode = true;
  603.                     break;
  604.                 default:
  605.                     writer.append(ch);
  606.                     break;
  607.                 }
  608.                 continue;
  609.             }
  610.             else if (ch == '//')
  611.             {
  612.                 hadSlash = true;
  613.                 continue;
  614.             }
  615.             writer.append(ch);
  616.         }
  617.         if (hadSlash)
  618.         {
  619.             // then we're in the weird case of a / at the end of the
  620.             // string, let's output it anyway.
  621.             writer.append('//');
  622.         }
  623.         return writer.toString();
  624.     }
  625.     /**
  626.      * Check to see if the given word is reserved or a bad idea in any known
  627.      * version of JavaScript.
  628.      * @param name The word to check
  629.      * @return false if the word is not reserved
  630.      */
  631.     public static boolean isReservedWord(String name)
  632.     {
  633.         return reserved.contains(name);
  634.     }
  635.     /**
  636.      * The array of javascript reserved words
  637.      */
  638.     private static final String[] RESERVED_ARRAY = new String[]
  639.     {
  640.         // Reserved and used at ECMAScript 4
  641.         "as",
  642.         "break",
  643.         "case",
  644.         "catch",
  645.         "class",
  646.         "const",
  647.         "continue",
  648.         "default",
  649.         "delete",
  650.         "do",
  651.         "else",
  652.         "export",
  653.         "extends",
  654.         "false",
  655.         "finally",
  656.         "for",
  657.         "function",
  658.         "if",
  659.         "import",
  660.         "in",
  661.         "instanceof",
  662.         "is",
  663.         "namespace",
  664.         "new",
  665.         "null",
  666.         "package",
  667.         "private",
  668.         "public",
  669.         "return",
  670.         "super",
  671.         "switch",
  672.         "this",
  673.         "throw",
  674.         "true",
  675.         "try",
  676.         "typeof",
  677.         "use",
  678.         "var",
  679.         "void",
  680.         "while",
  681.         "with",
  682.         // Reserved for future use at ECMAScript 4
  683.         "abstract",
  684.         "debugger",
  685.         "enum",
  686.         "goto",
  687.         "implements",
  688.         "interface",
  689.         "native",
  690.         "protected",
  691.         "synchronized",
  692.         "throws",
  693.         "transient",
  694.         "volatile",
  695.         // Reserved in ECMAScript 3, unreserved at 4 best to avoid anyway
  696.         "boolean",
  697.         "byte",
  698.         "char",
  699.         "double",
  700.         "final",
  701.         "float",
  702.         "int",
  703.         "long",
  704.         "short",
  705.         "static",
  706.         // I have seen the folowing list as 'best avoided for function names'
  707.         // but it seems way to all encompassing, so I'm not going to include it
  708.         /*
  709.         "alert", "anchor", "area", "arguments", "array", "assign", "blur",
  710.         "boolean", "button", "callee", "caller", "captureevents", "checkbox",
  711.         "clearinterval", "cleartimeout", "close", "closed", "confirm",
  712.         "constructor", "date", "defaultstatus", "document", "element", "escape",
  713.         "eval", "fileupload", "find", "focus", "form", "frame", "frames",
  714.         "getclass", "hidden", "history", "home", "image", "infinity",
  715.         "innerheight", "isfinite", "innerwidth", "isnan", "java", "javaarray",
  716.         "javaclass", "javaobject", "javapackage", "length", "link", "location",
  717.         "locationbar", "math", "menubar", "mimetype", "moveby", "moveto",
  718.         "name", "nan", "navigate", "navigator", "netscape", "number", "object",
  719.         "onblur", "onerror", "onfocus", "onload", "onunload", "open", "opener",
  720.         "option", "outerheight", "outerwidth", "packages", "pagexoffset",
  721.         "pageyoffset", "parent", "parsefloat", "parseint", "password",
  722.         "personalbar", "plugin", "print", "prompt", "prototype", "radio", "ref",
  723.         "regexp", "releaseevents", "reset", "resizeby", "resizeto",
  724.         "routeevent", "scroll", "scrollbars", "scrollby", "scrollto", "select",
  725.         "self", "setinterval", "settimeout", "status", "statusbar", "stop",
  726.         "string", "submit", "sun", "taint",  "text", "textarea", "toolbar",
  727.         "top", "tostring", "unescape", "untaint", "unwatch", "valueof", "watch",
  728.         "window",
  729.         */
  730.     };
  731.     private static SortedSet reserved = new TreeSet();
  732.     /**
  733.      * For easy access ...
  734.      */
  735.     static
  736.     {
  737.         // The Javascript reserved words array so we don't generate illegal javascript
  738.         reserved.addAll(Arrays.asList(RESERVED_ARRAY));
  739.     }
  740.     private static final String SPACE = " ";
  741.     /**
  742.      * How does a multi line comment start?
  743.      */
  744.     private static final String COMMENT_ML_START = "/*";
  745.     /**
  746.      * How does a multi line comment end?
  747.      */
  748.     private static final String COMMENT_ML_END = "*/";
  749.     /**
  750.      * How does a single line comment start?
  751.      */
  752.     private static final String COMMENT_SL_START = "//";
  753.     /**
  754.      * Sometimes we need to retain the comment because it has special meaning
  755.      */
  756.     private static final String COMMENT_RETAIN = "#DWR";
  757.     /**
  758.      * The log stream
  759.      */
  760.     private static final Log log = LogFactory.getLog(JavascriptUtil.class);
  761. }


    需要的JSON类我已经放到共享,你可以从
    http://download.csdn.net/source/879579

    下载
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值