Java tutorial
/* * Copyright (C) 2008 feilong * * 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.feilong.tools.jsonlib; import static org.apache.commons.lang3.StringUtils.EMPTY; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.TreeMap; import org.apache.commons.collections4.IteratorUtils; import org.apache.commons.lang3.ClassUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.reflect.FieldUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.feilong.core.bean.ConvertUtil; import com.feilong.core.lang.ArrayUtil; import com.feilong.core.lang.ClassUtil; import com.feilong.core.lang.ObjectUtil; import com.feilong.core.lang.reflect.FieldUtil; import com.feilong.tools.jsonlib.filters.ArrayContainsPropertyNamesPropertyFilter; import com.feilong.tools.jsonlib.processor.DateJsonValueProcessor; import com.feilong.tools.jsonlib.processor.SensitiveWordsJsonValueProcessor; import com.feilong.tools.jsonlib.util.PropertyStrategyWrapper; import static com.feilong.core.Validator.isNotNullOrEmpty; import static com.feilong.core.Validator.isNullOrEmpty; import static com.feilong.core.DatePattern.COMMON_DATE; import static com.feilong.core.DatePattern.COMMON_DATE_AND_TIME; import static com.feilong.core.DatePattern.COMMON_TIME; import net.sf.ezmorph.MorpherRegistry; import net.sf.ezmorph.object.DateMorpher; import net.sf.json.JSON; import net.sf.json.JSONArray; import net.sf.json.JSONObject; import net.sf.json.JsonConfig; import net.sf.json.processors.JsonValueProcessor; import net.sf.json.util.CycleDetectionStrategy; import net.sf.json.util.JSONUtils; import net.sf.json.util.PropertySetStrategy; /** * json?. * * <h3>???:</h3> * <blockquote> * <table border="1" cellspacing="0" cellpadding="4" summary=""> * <tr style="background-color:#ccccff"> * <th align="left">:</th> * <th align="left">:</th> * </tr> * <tr valign="top"> * <td>{@link #format(Object)}</td> * <td>??json</td> * </tr> * <tr valign="top" style="background-color:#eeeeff"> * <td>{@link #toJSON(Object)}</td> * <td>Bean?Map?????Json.</td> * </tr> * </table> * </blockquote> * * <h3>json-lib format map json?//map</h3> * * <blockquote> * <p> * see {@link net.sf.json.JSONObject#_fromMap(Map, JsonConfig)} * </p> * <ul> * <li>key?null</li> * <li>key?"null" </li> * </ul> * </blockquote> * * * <h3>??jar:</h3> * * <blockquote> * * <pre class="code"> * {@code * <groupId>net.sf.json-lib</groupId> * <artifactId>json-lib</artifactId> * } * * ? xml,? * * {@code * <groupId>xom</groupId> * <artifactId>xom</artifactId> * } * * ??????XML, xstreamXML?? * </pre> * * </blockquote> * * @author <a href="http://feitianbenyue.iteye.com/">feilong</a> * @see net.sf.json.JSONSerializer#toJSON(Object, JsonConfig) * * @see net.sf.json.JSONObject * @see net.sf.json.JSONArray * @see net.sf.json.JSONNull * @since 1.0.5 */ //XXX @deprecated net.sf.json-lib Non-maintenance,will use Jackson instead public final class JsonUtil { /** The Constant LOGGER. */ private static final Logger LOGGER = LoggerFactory.getLogger(JsonUtil.class); /** The Constant DEFAULT_JSON_CONFIG. */ private static final JsonConfig DEFAULT_JSON_CONFIG; //*********************************************************************************** /** The Constant SENSITIVE_WORDS_JSONVALUE_PROCESSOR. */ private static final SensitiveWordsJsonValueProcessor SENSITIVE_WORDS_JSONVALUE_PROCESSOR = new SensitiveWordsJsonValueProcessor(); /** The Constant SENSITIVE_WORDS_PROPERTY_NAMES. */ private static final String[] SENSITIVE_WORDS_PROPERTY_NAMES = { "password", "key" }; /** Don't let anyone instantiate this class. */ private JsonUtil() { //AssertionError?. ?????. ???. //see Effective Java 2nd throw new AssertionError("No " + getClass().getName() + " instances for you!"); } //*********************************************************************************** /** * ??. */ static { // MorpherRegistry morpherRegistry = JSONUtils.getMorpherRegistry(); // ???,?Json?? morpherRegistry.registerMorpher( new DateMorpher(ConvertUtil.toArray(COMMON_DATE_AND_TIME, COMMON_TIME, COMMON_DATE))); DEFAULT_JSON_CONFIG = getDefaultJsonConfig(); } //***************************format******************************************************** // [start] format /** * <code>obj</code> ??json. * * <p> * ??json??? * </p> * * <h3>:</h3> * <blockquote> * * <pre class="code"> {"userAddresseList":[{"address":"?1188?H109-118"},{"address":"28025?802()"}],"userAddresses":[{"address":"?1188?H109-118"},{"address":"28025?802()"}],"date":"2016-06-09 17:40:28","password":"******","id":8,"nickName":[],"age":0,"name":"feilong","money":99999999,"attrMap":null,"userInfo":{"age":10},"loves":["?",""]} * </pre> * * <b>:</b> * * <pre class="code"> { "userAddresseList": [ {"address": "?1188?H109-118"}, {"address": "28025?802()"} ], "userAddresses": [ {"address": "?1188?H109-118"}, {"address": "28025?802()"} ], "date": "2016-06-09 17:40:28", "password": "******", "id": 8, "nickName": [], "age": 0, "name": "feilong", "money": 99999999, "attrMap": null, "userInfo": {"age": 10}, "loves": [ "?", "" ] } * * </pre> * * </blockquote> * * <h3> <code>indent</code>:</h3> * * <blockquote> * <p> * toString(4,4) * </p> * * <p> * ?? <code>indent</code>,? {@link #format(Object, int, int)} {@link #format(Object, JsonConfig, int, int)} * {@link #format(Object, JsonFormatConfig, int, int)} * </p> * </blockquote> * * @param obj * * @return <code>obj</code> null, {@link StringUtils#EMPTY}<br> * @see #format(Object, JsonFormatConfig) */ public static String format(Object obj) { return format(obj, (JsonFormatConfig) null); } /** * map ??,request?, map?json??. * * <h3>?:</h3> * * <blockquote> * <ul> * <li> inputMap? simpleMap(<span style="color:red">inputMap??</span>)</li> * <li>?simpleMap {@link TreeMap},?json key??</li> * </ul> * </blockquote> * * <h3>?:</h3> * * <blockquote> * <ul> * <li>value isPrimitiveOrWrapper, ? simpleMap</li> * <li>? {@link String#valueOf(Object)} ?simpleMap</li> * </ul> * </blockquote>. * * @param <K> * the key type * @param <V> * the value type * @param inputMap * the input map * @return <code>inputMap</code> null, {@link StringUtils#EMPTY}<br> * @since 1.3.0 */ public static <K, V> String formatSimpleMap(Map<K, V> inputMap) { return null == inputMap ? EMPTY : formatSimpleMap(inputMap, (Class<?>) null); } /** * map ??,request?, map?json??. * * <h3>?:</h3> * * <blockquote> * <ul> * <li> inputMap? simpleMap(<span style="color:red">inputMap??</span>)</li> * <li>?simpleMap {@link TreeMap},?json key??</li> * </ul> * </blockquote> * * <h3>?:</h3> * * <blockquote> * <ul> * <li>valueisPrimitiveOrWrapper,?simpleMap</li> * <li>?{@link String#valueOf(Object)}?simpleMap</li> * </ul> * </blockquote>. * * @param <K> * the key type * @param <V> * the value type * @param inputMap * the input map * @param allowFormatClassTypes * ,?,??json format * @return <code>inputMap</code> null, {@link StringUtils#EMPTY}<br> * @since 1.3.0 */ public static <K, V> String formatSimpleMap(Map<K, V> inputMap, Class<?>... allowFormatClassTypes) { if (null == inputMap) { return EMPTY; } Map<K, Object> simpleMap = new TreeMap<K, Object>(); for (Map.Entry<K, V> entry : inputMap.entrySet()) { V value = entry.getValue(); simpleMap.put(entry.getKey(), isAllowFormatType(value, allowFormatClassTypes) ? value : String.valueOf(value)); //? String.valueOf(value)valuenull "null" } return format(simpleMap); } /** * ? ?json(<b></b>?? <code>excludes</code>), toString(4, 4) . * * <p> * ,<b>?</b>?,see {@link #formatWithIncludes(Object, String...)} * </p> * * <h3>:</h3> * * <blockquote> * * <pre class="code"> * * User user = new User(); * * user.setPassword("123456"); * user.setId(8L); * user.setName("feilong"); * user.setDate(new Date()); * user.setMoney(toBigDecimal("99999999.00")); * * user.setLoves(toArray("?", "")); * user.setUserInfo(new UserInfo(10)); * * UserAddress userAddress1 = new UserAddress("?1188?H109-118"); * UserAddress userAddress2 = new UserAddress("28025?802()"); * * user.setUserAddresses(toArray(userAddress1, userAddress2)); * user.setUserAddresseList(toList(userAddress1, userAddress2)); * * LOGGER.debug(JsonUtil.format(USER, toArray("name", "loves", "attrMap", "userInfo", "userAddresses"))); * * </pre> * * <b>:</b> * * <pre class="code"> * { "userAddresseList": [ {"address": "?1188?H109-118"}, {"address": "28025?802()"} ], "date": "2016-07-17 16:04:35", "password": "******", "id": 8, "age": 0, "money": 99999999, "nickNames": [] } * </pre> * * </blockquote> * * @param obj * * @param excludes * ???json, excludes isNotNullOrEmpty,?setExcludes * @return <code>obj</code> null, {@link StringUtils#EMPTY}<br> * @see <a href="http://feitianbenyue.iteye.com/blog/2046877">java.lang.ClassCastException: JSON keys must be strings</a> */ public static String format(Object obj, String[] excludes) { return format(obj, excludes, 4, 4); } /** * ? ?json(<b></b>?? <code>excludes</code>),(<code>indentFactor</code> <code>indent</code>) . * * <p> * ,<b>?</b>?,see {@link #formatWithIncludes(Object, String...)} * </p> * * <h3>:</h3> * * <blockquote> * * <pre class="code"> * * User user = new User(); * * user.setPassword("123456"); * user.setId(8L); * user.setName("feilong"); * user.setDate(new Date()); * user.setMoney(toBigDecimal("99999999.00")); * * user.setLoves(toArray("?", "")); * user.setUserInfo(new UserInfo(10)); * * UserAddress userAddress1 = new UserAddress("?1188?H109-118"); * UserAddress userAddress2 = new UserAddress("28025?802()"); * * user.setUserAddresses(toArray(userAddress1, userAddress2)); * user.setUserAddresseList(toList(userAddress1, userAddress2)); * * LOGGER.debug(JsonUtil.format(USER, toArray("name", "loves", "attrMap", "userInfo", "userAddresses"), 0, 0)); * * </pre> * * <b>:</b> * * <pre class="code"> {"userAddresseList":[{"address":"?1188?H109-118"},{"address":"28025?802()"}],"date":"2016-07-17 16:05:34","password":"******","id":8,"age":0,"money":99999999,"nickNames":[]} * </pre> * * </blockquote> * * @param obj * the obj * @param excludes * ???json, excludes isNotNullOrEmpty,?setExcludes * @param indentFactor * the indent factor * @param indent * the indent * @return <code>obj</code> null, {@link StringUtils#EMPTY}<br> * @see #format(Object, JsonFormatConfig) * @see #buildJsonFormatConfig(String[], String[]) */ public static String format(Object obj, String[] excludes, Integer indentFactor, Integer indent) { return null == obj ? EMPTY : format(obj, buildJsonFormatConfig(excludes, null), indentFactor, indent); } /** * ? ?json(<b>?</b>?? <code>includes</code>). * * <p> * ,<b></b>?,see {@link #format(Object, String[])}? {@link #format(Object, String[], Integer, Integer)} * </p> * * <h3>:</h3> * * <blockquote> * * <pre class="code"> * * User user1 = new User("feilong1", 24); * user1.setNickNames(toArray("xin.jin", "shuai.ge")); * User user2 = new User("feilong2", 240); * user2.setNickNames(toArray("xin.jin", "shuai.ge")); * * List{@code <User>} list = toList(user1, user2); * * LOGGER.debug(JsonUtil.formatWithIncludes(list, "name", "age")); * * </pre> * * <b>:</b> * * <pre class="code"> [{ "age": 24, "name": "feilong1" }, { "age": 240, "name": "feilong2" } ] * </pre> * * </blockquote> * * @param obj * the obj * @param includes * the includes * @return <code>obj</code> null, {@link StringUtils#EMPTY}<br> * @see #format(Object, JsonFormatConfig) * @see #buildJsonFormatConfig(String[], String[]) * @since 1.0.8 */ public static String formatWithIncludes(Object obj, final String... includes) { return null == obj ? EMPTY : format(obj, buildJsonFormatConfig(null, includes)); } /** * Builds the json format config. * * @param excludes * the excludes * @param includes * the includes * @return the json format config * @since 1.6.3 */ private static JsonFormatConfig buildJsonFormatConfig(String[] excludes, String[] includes) { boolean noNeedBuild = isNullOrEmpty(excludes) && isNullOrEmpty(includes); return noNeedBuild ? null : new JsonFormatConfig(excludes, includes); } /** * ? ?json,(<code>indentFactor</code> <code>indent</code>) . * * <h3>:</h3> * * <blockquote> * * <pre class="code"> * * // >10 * Predicate<Integer> predicate = new ComparatorPredicate<Integer>(10, ComparatorUtils.<Integer> naturalComparator(), Criterion.LESS); * * List<Integer> result = CollectionsUtil.select(toList(1, 5, 10, 30, 55, 88, 1, 12, 3), predicate); * LOGGER.debug(JsonUtil.format(result, 0, 0)); * * </pre> * * <b>:</b> * * <pre class="code"> * [30,55,88,12] * </pre> * * <hr> * * <pre class="code"> * LOGGER.debug(JsonUtil.format(result, 4, 4));// = LOGGER.debug(JsonUtil.format(result)) * </pre> * * <b>:</b> * * <pre class="code"> * [ 30, 55, 88, 12 ] * </pre> * * </blockquote> * * @param obj * the obj * @param indentFactor * the indent factor * @param indent * the indent * @return the string * @since 1.2.2 */ public static String format(Object obj, int indentFactor, int indent) { return format(obj, (JsonConfig) null, indentFactor, indent); } /** * ? <code>JsonFormatConfig</code> ???json. * * <h3>:</h3> * * <blockquote> * * <pre class="code"> * * User user = new User("feilong1", 24); * user.setPassword("123456"); * user.setMoney(toBigDecimal("99999999.00")); * * Map{@code <String, JsonValueProcessor>} propertyNameAndJsonValueProcessorMap = new HashMap{@code <String, JsonValueProcessor>}(); * propertyNameAndJsonValueProcessorMap.put("password", new SensitiveWordsJsonValueProcessor()); * propertyNameAndJsonValueProcessorMap.put("money", new BigDecimalJsonValueProcessor()); * * JsonFormatConfig jsonFormatConfig = new JsonFormatConfig(); * jsonFormatConfig.setPropertyNameAndJsonValueProcessorMap(propertyNameAndJsonValueProcessorMap); * * LOGGER.debug(JsonUtil.format(user, jsonFormatConfig)); * * </pre> * * <b>:</b> * * <pre class="code"> * { "userAddresseList": [], "userAddresses": [], "date": null, "password": "******", "id": 0, "age": 24, "name": "feilong1", "money": "99999999.00", "attrMap": null, "userInfo": {"age": 0}, "nickNames": [], "loves": [] } * </pre> * * <p> * ,<code>password</code> {@link SensitiveWordsJsonValueProcessor} ?? * </p> * * </blockquote> * * @param obj * the obj * @param jsonFormatConfig * the json format config * @return <code>obj</code> null, {@link StringUtils#EMPTY}<br> * @since 1.2.2 */ public static String format(Object obj, JsonFormatConfig jsonFormatConfig) { return format(obj, jsonFormatConfig, 4, 4); } /** * Format. * * @param obj * the obj * @param jsonFormatConfig * the json format config * @param indentFactor * the indent factor * @param indent * the indent * @return <code>obj</code> null, {@link StringUtils#EMPTY}<br> * @since 1.2.2 */ public static String format(Object obj, JsonFormatConfig jsonFormatConfig, int indentFactor, int indent) { if (null == jsonFormatConfig) { return format(obj, (JsonConfig) null, indentFactor, indent); } JsonConfig jsonConfig = getDefaultJsonConfig(); //value? Map<String, JsonValueProcessor> propertyNameAndJsonValueProcessorMap = jsonFormatConfig .getPropertyNameAndJsonValueProcessorMap(); if (isNotNullOrEmpty(propertyNameAndJsonValueProcessorMap)) { for (Map.Entry<String, JsonValueProcessor> entry : propertyNameAndJsonValueProcessorMap.entrySet()) { jsonConfig.registerJsonValueProcessor(entry.getKey(), entry.getValue()); } } // if (isNotNullOrEmpty(jsonFormatConfig.getExcludes())) { jsonConfig.setExcludes(jsonFormatConfig.getExcludes()); } //? if (isNotNullOrEmpty(jsonFormatConfig.getIncludes())) { jsonConfig.setJsonPropertyFilter( new ArrayContainsPropertyNamesPropertyFilter(jsonFormatConfig.getIncludes())); } return format(obj, jsonConfig, indentFactor, indent); } /** * ? <code>obj</code> ?field ??. * * <h3>??:</h3> * * <blockquote> * <ol> * <li>field {@link SensitiveWords}, {@link SensitiveWordsJsonValueProcessor}??</li> * </ol> * </blockquote> * * @param obj * the obj * @return <code>obj</code> null, {@link StringUtils#EMPTY}<br> * ?? field name value map {@link FieldUtil#getAllFieldNameAndValueMap(Object, String...)} * {@link #format(Object, JsonFormatConfig)},?,? {@link SensitiveWords} * @see FieldUtil#getAllFieldNameAndValueMap(Object, String...) * @see org.apache.commons.lang3.reflect.FieldUtils#getFieldsListWithAnnotation(Class, Class) * @since 1.5.6 */ public static String formatObjectFieldsNameAndValueMap(Object obj) { return null == obj ? EMPTY : format(FieldUtil.getAllFieldNameAndValueMap(obj), buildJsonFormatConfig(obj)); } /** * Builds the json format config. * * @param obj * the obj * @return the json format config * @since 1.6.3 */ private static JsonFormatConfig buildJsonFormatConfig(Object obj) { List<Field> fieldsListWithAnnotation = FieldUtils.getFieldsListWithAnnotation(obj.getClass(), SensitiveWords.class); if (isNotNullOrEmpty(fieldsListWithAnnotation)) { Map<String, JsonValueProcessor> propertyNameAndJsonValueProcessorMap = new HashMap<String, JsonValueProcessor>(); for (Field field : fieldsListWithAnnotation) { propertyNameAndJsonValueProcessorMap.put(field.getName(), SENSITIVE_WORDS_JSONVALUE_PROCESSOR); } return new JsonFormatConfig(propertyNameAndJsonValueProcessorMap); } return null; } /** * Make a prettyprinted JSON text. * * <p> * Warning: This method assumes that the data structure is acyclical. * </p> * * @param obj * the obj * @param jsonConfig * the json config * @param indentFactor * The number of spaces to add to each level of indentation. * @param indent * The indentation of the top level. * @return <code>obj</code> null, {@link StringUtils#EMPTY}<br> * a printable,displayable,transmittable representation of the object,<br> * beginning with{ (left brace) and ending with }(right brace). * @since 1.0.8 */ private static String format(Object obj, JsonConfig jsonConfig, int indentFactor, int indent) { return null == obj ? EMPTY : toJSON(obj, jsonConfig).toString(indentFactor, indent); } // [end] // [start]toJSON /** * Bean?Map?????Json. * * @param obj * the obj * @return the jSON * @see #toJSON(Object, JsonConfig) */ static JSON toJSON(Object obj) { return toJSON(obj, null); } /** * Bean?Map?????Json. * * <p> * <code>null==jsonConfig</code>, {@link #DEFAULT_JSON_CONFIG} * </p> * * @param obj * the obj * @param jsonConfig * the json config * @return the jSON * @see net.sf.json.JSONArray#fromObject(Object, JsonConfig) * @see net.sf.json.JSONObject#fromObject(Object, JsonConfig) * @see net.sf.json.util.JSONUtils#isArray(Object) * @see java.lang.Class#isEnum() * @see net.sf.json.JsonConfig#registerJsonValueProcessor(Class, JsonValueProcessor) * @see org.apache.commons.collections4.IteratorUtils#toList(Iterator) * @see org.apache.commons.collections4.IteratorUtils#toList(Iterator, int) * @see net.sf.json.JSONSerializer#toJSON(Object) */ static JSON toJSON(Object obj, JsonConfig jsonConfig) { JsonConfig useJsonConfig = ObjectUtils.defaultIfNull(jsonConfig, DEFAULT_JSON_CONFIG); registerDefaultJsonValueProcessor(useJsonConfig); if (isNeedConvertToJSONArray(obj)) { Object arrayJsonObject = obj instanceof Iterator ? IteratorUtils.toList((Iterator<?>) obj) : obj; return toJSONArray(arrayJsonObject, useJsonConfig); } return toJSONObject(obj, useJsonConfig); } /** * ??? JSONArray. * * @param obj * the obj * @return true, if is array * @see net.sf.json.JSONArray#_fromJSONTokener(net.sf.json.util.JSONTokener, JsonConfig) * @since 1.7.2 */ private static boolean isNeedConvertToJSONArray(Object obj) { if (obj instanceof String) { String str = (String) obj; if (str.startsWith("[") && str.endsWith("]")) {// [] ? return true; } } return JSONUtils.isArray(obj) || //obj.getClass().isArray() || obj instanceof Collection || obj instanceof Object[] obj instanceof Enum || // obj.getClass().isEnum() null// object'isanEnum.UseJSONArrayinstead obj instanceof Iterator; } // [end] /** * ?. * * @param jsonConfig * the json config * @since 1.5.3 */ private static void registerDefaultJsonValueProcessor(JsonConfig jsonConfig) { for (String propertyName : SENSITIVE_WORDS_PROPERTY_NAMES) { jsonConfig.registerJsonValueProcessor(propertyName, SENSITIVE_WORDS_JSONVALUE_PROCESSOR); } } //******************************************************************************************** /** * To json array. * * @param json * the json * @return the JSON array * @see net.sf.json.JSONArray#fromObject(Object) * @since 1.4.0 */ private static JSONArray toJSONArray(String json) { return toJSONArray(json, new JsonConfig()); } /** * To json array. * * @param obj * Accepts JSON formatted strings, arrays, Collections and Enums. * @param useJsonConfig * the use json config * @return the JSON array * @see net.sf.json.JSONArray#fromObject(Object, JsonConfig) * @since 1.4.0 */ private static JSONArray toJSONArray(Object obj, JsonConfig useJsonConfig) { return JSONArray.fromObject(obj, useJsonConfig); } //**************toJSONObject******************** /** * To json object. * * @param json * the json * @return the JSON object * @see net.sf.json.JSONObject#fromObject(Object) * @since 1.4.0 */ private static JSONObject toJSONObject(String json) { return toJSONObject(json, new JsonConfig()); } /** * To json object. * * @param obj * Accepts JSON formatted strings, Maps, DynaBeans and JavaBeans * @param useJsonConfig * the use json config * @return the JSON object * @see net.sf.json.JSONObject#fromObject(Object, JsonConfig) * @since 1.4.0 */ private static JSONObject toJSONObject(Object obj, JsonConfig useJsonConfig) { return JSONObject.fromObject(obj, useJsonConfig); } // *****************************Array****************************************************** // [start]toArray /** * json,??. * * <h3>:</h3> * <blockquote> * * <pre class="code"> * String json = "[{'name':'get'},{'name':'set'}]"; * Person[] objArr = JsonUtil.toArray(json, Person.class); * * LOGGER.info(JsonUtil.format(objArr)); * </pre> * * <b>:</b> * * <pre class="code"> [{ "dateAttr": null, "name": "get" }, { "dateAttr": null, "name": "set" }] * * </pre> * * </blockquote> * * @param <T> * the generic type * @param json * e.g. [{'name':'get'},{'name':'set'}] * @param rootClass * e.g. Person.class,see {@link net.sf.json.JsonConfig#setRootClass(Class)} * @return Object[] * @see #toArray(String, Class, Map) */ public static <T> T[] toArray(String json, Class<T> rootClass) { return toArray(json, rootClass, null); } /** * json??,??Bean. * * <h3>:</h3> * <blockquote> * * <pre class="code"> * String json = "[{'data':[{'name':'get'}]},{'data':[{'name':'set'}]}]"; * Map{@code <String, Class<?>>} classMap = new HashMap{@code <String, Class<?>>}(); * classMap.put("data", Person.class); * * MyBean[] objArr = JsonUtil.toArray(json, MyBean.class, classMap); * LOGGER.info(JsonUtil.format(objArr)); * </pre> * * <b>:</b> * * <pre class="code"> [{ "id": 0, "data": [ { "dateAttr": null, "name": "get" }] },{ "id": 0, "data": [ { "dateAttr": null, "name": "set" }] }] * </pre> * * </blockquote> * * @param <T> * the generic type * @param json * e.g. [{'data':[{'name':'get'}]},{'data':[{'name':'set'}]}] * @param rootClass * e.g. MyBean.class,see {@link net.sf.json.JsonConfig#setRootClass(Class)} * @param classMap * e.g. classMap.put("data", Person.class) * @return T[] * @see net.sf.json.JSONArray#fromObject(Object) * @see net.sf.json.JSONArray#getJSONObject(int) * @see #toBean(Object, Class, Map) * @see java.lang.reflect.Array#newInstance(Class, int) */ public static <T> T[] toArray(String json, Class<T> rootClass, Map<String, Class<?>> classMap) { JSONArray jsonArray = toJSONArray(json); int size = jsonArray.size(); T[] t = ArrayUtil.newArray(rootClass, size); for (int i = 0; i < size; i++) { t[i] = toBean(jsonArray.getJSONObject(i), rootClass, classMap); } return t; } // [end] // *****************************List******************************************************** // [start]toList /** * json???,?Bean. * * <h3>:</h3> * <blockquote> * * <pre class="code"> * String json = "[{'name':'get'},{'name':'set'}]"; * List{@code <Person>} list = JsonUtil.toList(json, Person.class); * * LOGGER.info(JsonUtil.format(list)); * </pre> * * <b>:</b> * * <pre class="code"> [{ "dateAttr": null, "name": "get" }, { "dateAttr": null, "name": "set" } ] * </pre> * * </blockquote> * * @param <T> * the generic type * @param json * e.g. [{'name':'get'},{'name':'set'}] * @param rootClass * the klass,see {@link net.sf.json.JsonConfig#setRootClass(Class)} * @return List * @see #toList(String, Class, Map) */ public static <T> List<T> toList(String json, Class<T> rootClass) { return toList(json, rootClass, null); } /** * json???,???Bean. * * <h3>:</h3> * <blockquote> * * <pre class="code"> * String json = "[{'data':[{'name':'get'}]},{'data':[{'name':'set'}]}]"; * Map{@code <String, Class<?>>} classMap = new HashMap{@code <String, Class<?>>}(); * classMap.put("data", Person.class); * * List{@code <MyBean>} list = JsonUtil.toList(json, MyBean.class, classMap); * * LOGGER.debug(JsonUtil.format(list)); * </pre> * * <b>:</b> * * <pre class="code"> [{ "id": 0, "data": [ { "dateAttr": null, "name": "get" }] }, { "id": 0, "data": [ { "dateAttr": null, "name": "set" }] }] * </pre> * * </blockquote> * * @param <T> * the generic type * @param json * e.g. [{'data':[{'name':'get'}]},{'data':[{'name':'set'}]}] * @param rootClass * e.g. MyBean.class,see {@link net.sf.json.JsonConfig#setRootClass(Class)} * @param classMap * e.g. classMap.put("data", Person.class) * @return List * @see net.sf.json.JSONArray#getJSONObject(int) * @see net.sf.json.JSONArray#fromObject(Object) * @see #toBean(Object, Class, Map) */ public static <T> List<T> toList(String json, Class<T> rootClass, Map<String, Class<?>> classMap) { JSONArray jsonArray = toJSONArray(json); List<T> list = new ArrayList<T>(); for (int i = 0, j = jsonArray.size(); i < j; i++) { list.add(toBean(jsonArray.getJSONObject(i), rootClass, classMap)); } return list; } // [end] // ********************************Map****************************************************** // [start]toMap /** * ? json?map. * * <h3>:</h3> * <blockquote> * * <pre class="code"> * String json = "{'brandCode':'UA'}"; * Map{@code <String, Object>} map = JsonUtil.toMap(json); * LOGGER.info(JsonUtil.format(map)); * </pre> * * <b>:</b> * * <pre class="code"> * key brandCode,value UA map * </pre> * * <hr> * * <pre class="code"> * Map{@code <String, Integer>} map2 = JsonUtil.toMap("{'brandCode':55555}"); * LOGGER.info(JsonUtil.format(map2)); * </pre> * * <b>:</b> * * <pre class="code"> * {"brandCode": 55555} * </pre> * * </blockquote> * * <h3>?:</h3> * * <p> * unchecked,?? * </p> * * <blockquote> * * <pre class="code"> * Map{@code <String, Long>} map3 = JsonUtil.toMap("{'brandCode':55.555}"); * LOGGER.info(JsonUtil.format(map3)); * </pre> * * <b>:</b> * * <pre class="code"> * {"brandCode": 55.555} * </pre> * * </blockquote> * * @param <T> * the generic type * @param json * the json * @return <code>json</code> nullempty, {@link Collections#emptyMap()} * @see #toMap(String, Class) * @since 1.5.0 */ public static <T> Map<String, T> toMap(String json) { return toMap(json, null); } /** * json??map,mapBean. * * <p> * null==klass,json?value map value * </p> * * <h3>:</h3> * <blockquote> * * <pre class="code"> * String json = "{'data1':{'name':'get'},'data2':{'name':'set'}}"; * Map{@code <String, Person>} map = JsonUtil.toMap(json, Person.class); * LOGGER.info(JsonUtil.format(map)); * </pre> * * <b>:</b> * * <pre class="code"> {"data1":{ "name": "get" }, "data2":{ "name": "set" }} * </pre> * * <hr> * * <pre class="code"> * Map{@code <String, String>} map1 = JsonUtil.toMap("{'data1':{'name':'get'},'data2':{'name':'set'}}", null); * LOGGER.info(JsonUtil.format(map1)); * </pre> * * <b>:</b> * * <pre class="code"> * { * "data1": {"name": "get"}, * "data2": {"name": "set"} * } * </pre> * * </blockquote> * * @param <T> * the generic type * @param json * e.g. {'data1':{'name':'get'}, 'data2':{'name':'set'}} * @param rootClass * e.g. Person.class ,see {@link net.sf.json.JsonConfig#setRootClass(Class)} * @return <code>json</code> nullempty, {@link Collections#emptyMap()} * @see #toMap(String, Class, Map) */ public static <T> Map<String, T> toMap(String json, Class<T> rootClass) { return toMap(json, rootClass, null); } /** * json??map,mapBean??Bean. * * <p> * null==klass,json?value map value * </p> * * <h3>:</h3> * <blockquote> * * <pre class="code"> * String json = "{'mybean':{'data':[{'name':'get'}]}}"; * Map{@code <String, Class<?>>} classMap = new HashMap{@code <String, Class<?>>}(); * classMap.put("data", Person.class); * * Map{@code <String, MyBean>} map = JsonUtil.toMap(json, MyBean.class, classMap); * LOGGER.debug(JsonUtil.format(map)); * </pre> * * <b>:</b> * * <pre class="code"> {"mybean":{ "id": 0, "data": [{ "name": "get" }] }} * </pre> * * </blockquote> * * @param <T> * the generic type * @param json * e.g. {'mybean':{'data':[{'name':'get'}]}} * @param rootClass * e.g. MyBean.class ,see {@link net.sf.json.JsonConfig#setRootClass(Class)} * @param classMap * e.g. classMap.put("data", Person.class) * @return <code>json</code> nullempty, {@link Collections#emptyMap()}<br> * @see net.sf.json.JSONObject#keys() * @see #toBean(Object, Class, Map) */ @SuppressWarnings("unchecked") public static <T> Map<String, T> toMap(String json, Class<T> rootClass, Map<String, Class<?>> classMap) { LOGGER.trace("input json:[{}],rootClass:[{}]", json, rootClass); if (isNullOrEmpty(json)) { return Collections.emptyMap(); } Map<String, T> map = new HashMap<String, T>(); JSONObject jsonObject = toJSONObject(json); Iterator<String> keys = jsonObject.keys(); while (keys.hasNext()) { String key = keys.next(); Object value = jsonObject.get(key); LOGGER.debug("key:[{}],value:[{}],value type is:[{}]", key, value, value.getClass().getName()); map.put(key, null == rootClass ? (T) value : toBean(value, rootClass, classMap));//klassnull,??? } return map; } // [end] //*********************************************************************************** // [start]toBean /** * json,??. * * <h3>:</h3> * <blockquote> * * <pre class="code"> * String json = "{'name':'get','dateAttr':'2009-11-12'}"; * LOGGER.debug(JsonUtil.format(JsonUtil.toBean(json, Person.class))); * </pre> * * <b>:</b> * * <pre class="code"> * { * "dateAttr": "2009-11-12 00:00:00", * "name": "get" * } * </pre> * * </blockquote> * * @param <T> * the generic type * @param json * e.g. {'name':'get','dateAttr':'2009-11-12'}<br> * ? json,?JSONObject<br> * Accepts JSON formatted strings, Maps, DynaBeans and JavaBeans. <br> * ??: {@link JSONObject#fromObject(Object, JsonConfig)} * @param rootClass * e.g. Person.class,see {@link net.sf.json.JsonConfig#setRootClass(Class)} * @return the t */ public static <T> T toBean(Object json, Class<T> rootClass) { return toBean(json, rootClass, null); } /** * json??,??Bean. * * <h3>:</h3> * <blockquote> * * <pre class="code"> * String json = "{'data':[{'name':'get'},{'name':'set'}],'id':5}"; * Map{@code <String, Class<?>>} classMap = new HashMap{@code <String, Class<?>>}(); * classMap.put("data", Person.class); * * MyBean myBean = JsonUtil.toBean(json, MyBean.class, classMap); * LOGGER.info(JsonUtil.format(myBean)); * </pre> * * <b>:</b> * * <pre class="code"> { "id": 5, "data":[{ "dateAttr": null, "name": "get" },{ "dateAttr": null, "name": "set" } ] } * </pre> * * </blockquote> * * @param <T> * the generic type * @param json * e.g. {'data':[{'name':'get'},{'name':'set'}]} * @param rootClass * e.g. MyBean.class,see {@link net.sf.json.JsonConfig#setRootClass(Class)} * @param classMap * e.g. classMap.put("data", Person.class) * @return Object * @see #toBean(Object, JsonConfig) */ public static <T> T toBean(Object json, Class<T> rootClass, Map<String, Class<?>> classMap) { JSONObject jsonObject = JSONObject.fromObject(json); JsonConfig jsonConfig = getDefaultJsonConfig(); jsonConfig.setRootClass(rootClass); if (isNotNullOrEmpty(classMap)) { jsonConfig.setClassMap(classMap); } return toBean(jsonObject, jsonConfig); } /** * json,??. * * @param <T> * the generic type * @param json * the json * @param jsonConfig * the json config * @return the object * @see net.sf.json.JSONObject#toBean(JSONObject, JsonConfig) */ @SuppressWarnings("unchecked") private static <T> T toBean(Object json, JsonConfig jsonConfig) { JSONObject jsonObject = JSONObject.fromObject(json); // Ignore missing properties with Json-Lib // ?? Unknown property 'orderIdAndCodeMap' on class 'class // com.baozun.trade.web.controller.payment.result.command.PaymentResultEntity' jsonConfig.setPropertySetStrategy(new PropertyStrategyWrapper(PropertySetStrategy.DEFAULT)); return (T) JSONObject.toBean(jsonObject, jsonConfig); } // [end] //*********************************************************************************** /** * JsonConfig. * * @return the default json config * @see see net.sf.json.JsonConfig#DEFAULT_EXCLUDES * * @see net.sf.json.util.CycleDetectionStrategy#LENIENT */ private static JsonConfig getDefaultJsonConfig() { JsonConfig jsonConfig = new JsonConfig(); // ,?? There is a cycle in the hierarchy! //Returns empty array and null object jsonConfig.setCycleDetectionStrategy(CycleDetectionStrategy.LENIENT); //see net.sf.json.JsonConfig#DEFAULT_EXCLUDES //key "class","declaringClass","metaClass" jsonConfig.setIgnoreDefaultExcludes(false); //See javax.persistence.Transient //jsonConfig.setIgnoreJPATransient(true); //see Modifier.TRANSIENT //jsonConfig.setIgnoreTransientFields(true); //jsonConfig.setIgnorePublicFields(false); // ? jsonConfig.registerJsonValueProcessor(Date.class, new DateJsonValueProcessor(COMMON_DATE_AND_TIME)); // java.lang.ClassCastException: JSON keys must be strings // see http://feitianbenyue.iteye.com/blog/2046877 jsonConfig.setAllowNonStringKeys(true); return jsonConfig; } /** * ??json format. * * @param <V> * the value type * @param value * the value * @param allowClassTypes * the allow class types * @return true, if checks if is allow format type * @since 1.4.0 */ private static <V> boolean isAllowFormatType(V value, Class<?>... allowClassTypes) { if (null == value) {//null ? format return true; } Class<?> klassClass = value.getClass(); return ClassUtils.isPrimitiveOrWrapper(klassClass) // || String.class == klassClass // || ObjectUtil.isArray(value)//XXX ?? || ClassUtil.isInstanceAnyClass(value, allowClassTypes)// ; } }