struts2 json 定义全局Date格式

使用struts2的json插件时,自定义日期格式常用的方式是在get属性上添加@JSON注解,这个对于少量Date属性还可以,但是如果date字段多了,总不可能去给每个date get方法添加json注解吧!

发现极大不便后查看了sturts-plugin.xml 中的json-default定义,源码跟踪到json拦截器内部一点发现都没有,自定义

org.apache.struts2.json.JSONPopulator中的dateFormatter属性完全不起效果。但是在同一个包下:org.apache.struts2.json 发现了类:JSONWriter 在这里才找到了一些端倪

将源码中的

 
    /**
     * Add date to buffer
     */
    protected void date(Date date, Method method) {
        JSON json = null;
        if (method != null)
            json = method.getAnnotation(JSON.class);
        if (this.formatter == null)
            this.formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        
        DateFormat formatter = (json != null) && (json.format().length() > 0) ? new SimpleDateFormat(json
                .format()) : this.formatter;
        this.string(formatter.format(date));
    }
SimpleDateFormat 格式改成自定义日期格式即可,这样全局json 日期格式就自定义完成了!
注意:覆盖时只需要自定义包:org.apache.struts2.json将修改后的JSONWriter放到包下即可,没有必要去修改插件中的源码信息 


下面附上整个类的源码:


/*
 * $Id$
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.apache.struts2.json;

import com.opensymphony.xwork2.util.logging.Logger;
import com.opensymphony.xwork2.util.logging.LoggerFactory;
import org.apache.struts2.json.annotations.JSON;
import org.apache.struts2.json.annotations.JSONFieldBridge;
import org.apache.struts2.json.annotations.JSONParameter;
import org.apache.struts2.json.bridge.FieldBridge;
import org.apache.struts2.json.bridge.ParameterizedBridge;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.text.CharacterIterator;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.text.StringCharacterIterator;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Pattern;

/**
 * 

* Serializes an object into JavaScript Object Notation (JSON). If cyclic * references are detected they will be nulled out. *

*/ public class JSONWriter { private static final Logger LOG = LoggerFactory.getLogger(JSONWriter.class); /** * By default, enums are serialised as name=value pairs */ public static final boolean ENUM_AS_BEAN_DEFAULT = false; private static char[] hex = "0123456789ABCDEF".toCharArray(); private static final ConcurrentMap, BeanInfo> BEAN_INFO_CACHE_IGNORE_HIERARCHY = new ConcurrentHashMap, BeanInfo>(); private static final ConcurrentMap, BeanInfo> BEAN_INFO_CACHE = new ConcurrentHashMap, BeanInfo>(); private StringBuilder buf = new StringBuilder(); private Stack stack = new Stack(); private boolean ignoreHierarchy = true; private Object root; private boolean buildExpr = true; private String exprStack = ""; private Collection excludeProperties; private Collection includeProperties; private DateFormat formatter; private boolean enumAsBean = ENUM_AS_BEAN_DEFAULT; private boolean excludeNullProperties; /** * @param object Object to be serialized into JSON * @return JSON string for object * @throws JSONException */ public String write(Object object) throws JSONException { return this.write(object, null, null, false); } /** * @param object Object to be serialized into JSON * @return JSON string for object * @throws JSONException */ public String write(Object object, Collection excludeProperties, Collection includeProperties, boolean excludeNullProperties) throws JSONException { this.excludeNullProperties = excludeNullProperties; this.buf.setLength(0); this.root = object; this.exprStack = ""; this.buildExpr = ((excludeProperties != null) && !excludeProperties.isEmpty()) || ((includeProperties != null) && !includeProperties.isEmpty()); this.excludeProperties = excludeProperties; this.includeProperties = includeProperties; this.value(object, null); return this.buf.toString(); } /** * Detect cyclic references */ protected void value(Object object, Method method) throws JSONException { if (object == null) { this.add("null"); return; } if (this.stack.contains(object)) { Class clazz = object.getClass(); // cyclic reference if (clazz.isPrimitive() || clazz.equals(String.class)) { this.process(object, method); } else { if (LOG.isDebugEnabled()) { LOG.debug("Cyclic reference detected on " + object); } this.add("null"); } return; } this.process(object, method); } /** * Serialize object into json */ protected void process(Object object, Method method) throws JSONException { this.stack.push(object); if (object instanceof Class) { this.string(object); } else if (object instanceof Boolean) { this.bool((Boolean) object); } else if (object instanceof Number) { this.add(object); } else if (object instanceof String) { this.string(object); } else if (object instanceof Character) { this.string(object); } else if (object instanceof Map) { this.map((Map) object, method); } else if (object.getClass().isArray()) { this.array(object, method); } else if (object instanceof Iterable) { this.array(((Iterable) object).iterator(), method); } else if (object instanceof Date) { this.date((Date) object, method); } else if (object instanceof Calendar) { this.date(((Calendar) object).getTime(), method); } else if (object instanceof Locale) { this.string(object); } else if (object instanceof Enum) { this.enumeration((Enum) object); } else { processCustom(object, method); } this.stack.pop(); } /** * Serialize custom object into json */ protected void processCustom(Object object, Method method) throws JSONException { this.bean(object); } /** * Instrospect bean and serialize its properties */ protected void bean(Object object) throws JSONException { this.add("{"); BeanInfo info; try { Class clazz = object.getClass(); info = ((object == this.root) && this.ignoreHierarchy) ? getBeanInfoIgnoreHierarchy(clazz) : getBeanInfo(clazz); PropertyDescriptor[] props = info.getPropertyDescriptors(); boolean hasData = false; for (PropertyDescriptor prop : props) { String name = prop.getName(); Method accessor = prop.getReadMethod(); Method baseAccessor = findBaseAccessor(clazz, accessor); if (baseAccessor != null) { if (baseAccessor.isAnnotationPresent(JSON.class)) { JSONAnnotationFinder jsonFinder = new JSONAnnotationFinder(baseAccessor).invoke(); if (!jsonFinder.shouldSerialize()) continue; if (jsonFinder.getName() != null) { name = jsonFinder.getName(); } } // ignore "class" and others if (this.shouldExcludeProperty(prop)) { continue; } String expr = null; if (this.buildExpr) { expr = this.expandExpr(name); if (this.shouldExcludeProperty(expr)) { continue; } expr = this.setExprStack(expr); } Object value = accessor.invoke(object); if (baseAccessor.isAnnotationPresent(JSONFieldBridge.class)) { value = getBridgedValue(baseAccessor, value); } boolean propertyPrinted = this.add(name, value, accessor, hasData); hasData = hasData || propertyPrinted; if (this.buildExpr) { this.setExprStack(expr); } } } // special-case handling for an Enumeration - include the name() as // a property */ if (object instanceof Enum) { Object value = ((Enum) object).name(); this.add("_name", value, object.getClass().getMethod("name"), hasData); } } catch (Exception e) { throw new JSONException(e); } this.add("}"); } protected BeanInfo getBeanInfoIgnoreHierarchy(final Class clazz) throws IntrospectionException { BeanInfo beanInfo = BEAN_INFO_CACHE_IGNORE_HIERARCHY.get(clazz); if (beanInfo != null) { return beanInfo; } beanInfo = Introspector.getBeanInfo(clazz, clazz.getSuperclass()); BEAN_INFO_CACHE_IGNORE_HIERARCHY.put(clazz, beanInfo); return beanInfo; } protected BeanInfo getBeanInfo(final Class clazz) throws IntrospectionException { BeanInfo beanInfo = BEAN_INFO_CACHE.get(clazz); if (beanInfo != null) { return beanInfo; } beanInfo = Introspector.getBeanInfo(clazz); BEAN_INFO_CACHE.put(clazz, beanInfo); return beanInfo; } protected Object getBridgedValue(Method baseAccessor, Object value) throws InstantiationException, IllegalAccessException { JSONFieldBridge fieldBridgeAnn = baseAccessor.getAnnotation(JSONFieldBridge.class); if (fieldBridgeAnn != null) { Class impl = fieldBridgeAnn.impl(); FieldBridge instance = (FieldBridge) impl.newInstance(); if (fieldBridgeAnn.params().length > 0 && ParameterizedBridge.class.isAssignableFrom(impl)) { Map params = new HashMap(fieldBridgeAnn.params().length); for (JSONParameter param : fieldBridgeAnn.params()) { params.put(param.name(), param.value()); } ((ParameterizedBridge) instance).setParameterValues(params); } value = instance.objectToString(value); } return value; } protected Method findBaseAccessor(Class clazz, Method accessor) { Method baseAccessor = null; if (clazz.getName().contains("$$EnhancerByCGLIB$$")) { try { baseAccessor = Thread.currentThread().getContextClassLoader().loadClass( clazz.getName().substring(0, clazz.getName().indexOf("$$"))).getMethod( accessor.getName(), accessor.getParameterTypes()); } catch (Exception ex) { LOG.debug(ex.getMessage(), ex); } } else if (clazz.getName().contains("$$_javassist")) { try { baseAccessor = Class.forName( clazz.getName().substring(0, clazz.getName().indexOf("_$$"))) .getMethod(accessor.getName(), accessor.getParameterTypes()); } catch (Exception ex) { LOG.debug(ex.getMessage(), ex); } } else { return accessor; } return baseAccessor; } /** * Instrospect an Enum and serialize it as a name/value pair or as a bean * including all its own properties */ protected void enumeration(Enum enumeration) throws JSONException { if (enumAsBean) { this.bean(enumeration); } else { this.string(enumeration.name()); } } protected boolean shouldExcludeProperty(PropertyDescriptor prop) throws SecurityException, NoSuchFieldException { String name = prop.getName(); return name.equals("class") || name.equals("declaringClass") || name.equals("cachedSuperClass") || name.equals("metaClass"); } protected String expandExpr(int i) { return this.exprStack + "[" + i + "]"; } protected String expandExpr(String property) { if (this.exprStack.length() == 0) { return property; } return this.exprStack + "." + property; } protected String setExprStack(String expr) { String s = this.exprStack; this.exprStack = expr; return s; } protected boolean shouldExcludeProperty(String expr) { if (this.excludeProperties != null) { for (Pattern pattern : this.excludeProperties) { if (pattern.matcher(expr).matches()) { if (LOG.isDebugEnabled()) { LOG.debug("Ignoring property because of exclude rule: " + expr); } return true; } } } if (this.includeProperties != null) { for (Pattern pattern : this.includeProperties) { if (pattern.matcher(expr).matches()) { return false; } } if (LOG.isDebugEnabled()){ LOG.debug("Ignoring property because of include rule: " + expr); } return true; } return false; } /** * Add name/value pair to buffer */ protected boolean add(String name, Object value, Method method, boolean hasData) throws JSONException { if (excludeNullProperties && value == null) { return false; } if (hasData) { this.add(','); } this.add('"'); this.add(name); this.add("\":"); this.value(value, method); return true; } /** * Add map to buffer */ protected void map(Map map, Method method) throws JSONException { this.add("{"); Iterator it = map.entrySet().iterator(); boolean warnedNonString = false; // one report per map boolean hasData = false; while (it.hasNext()) { Map.Entry entry = (Map.Entry) it.next(); if (excludeNullProperties && entry.getValue() == null) { continue; } Object key = entry.getKey(); if (key == null) { LOG.error("Cannot build expression for null key in #0", exprStack); continue; } String expr = null; if (this.buildExpr) { expr = this.expandExpr(key.toString()); if (this.shouldExcludeProperty(expr)) { continue; } expr = this.setExprStack(expr); } if (hasData) { this.add(','); } hasData = true; if (!warnedNonString && !(key instanceof String)) { if (LOG.isWarnEnabled()) { LOG.warn("JavaScript doesn't support non-String keys, using toString() on #0", key.getClass().getName()); } warnedNonString = true; } this.value(key.toString(), method); this.add(":"); this.value(entry.getValue(), method); if (this.buildExpr) { this.setExprStack(expr); } } this.add("}"); } /** * Add date to buffer */ protected void date(Date date, Method method) { JSON json = null; if (method != null) json = method.getAnnotation(JSON.class); if (this.formatter == null) this.formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); DateFormat formatter = (json != null) && (json.format().length() > 0) ? new SimpleDateFormat(json .format()) : this.formatter; this.string(formatter.format(date)); } /** * Add array to buffer */ protected void array(Iterator it, Method method) throws JSONException { this.add("["); boolean hasData = false; for (int i = 0; it.hasNext(); i++) { String expr = null; if (this.buildExpr) { expr = this.expandExpr(i); if (this.shouldExcludeProperty(expr)) { it.next(); continue; } expr = this.setExprStack(expr); } if (hasData) { this.add(','); } hasData = true; this.value(it.next(), method); if (this.buildExpr) { this.setExprStack(expr); } } this.add("]"); } /** * Add array to buffer */ protected void array(Object object, Method method) throws JSONException { this.add("["); int length = Array.getLength(object); boolean hasData = false; for (int i = 0; i < length; ++i) { String expr = null; if (this.buildExpr) { expr = this.expandExpr(i); if (this.shouldExcludeProperty(expr)) { continue; } expr = this.setExprStack(expr); } if (hasData) { this.add(','); } hasData = true; this.value(Array.get(object, i), method); if (this.buildExpr) { this.setExprStack(expr); } } this.add("]"); } /** * Add boolean to buffer */ protected void bool(boolean b) { this.add(b ? "true" : "false"); } /** * escape characters */ protected void string(Object obj) { this.add('"'); CharacterIterator it = new StringCharacterIterator(obj.toString()); for (char c = it.first(); c != CharacterIterator.DONE; c = it.next()) { if (c == '"') { this.add("\\\""); } else if (c == '\\') { this.add("\\\\"); } else if (c == '/') { this.add("\\/"); } else if (c == '\b') { this.add("\\b"); } else if (c == '\f') { this.add("\\f"); } else if (c == '\n') { this.add("\\n"); } else if (c == '\r') { this.add("\\r"); } else if (c == '\t') { this.add("\\t"); } else if (Character.isISOControl(c)) { this.unicode(c); } else { this.add(c); } } this.add('"'); } /** * Add object to buffer */ protected void add(Object obj) { this.buf.append(obj); } /** * Add char to buffer */ protected void add(char c) { this.buf.append(c); } /** * Represent as unicode * * @param c character to be encoded */ protected void unicode(char c) { this.add("\\u"); int n = c; for (int i = 0; i < 4; ++i) { int digit = (n & 0xf000) >> 12; this.add(hex[digit]); n <<= 4; } } public void setIgnoreHierarchy(boolean ignoreHierarchy) { this.ignoreHierarchy = ignoreHierarchy; } /** * If true, an Enum is serialized as a bean with a special property * _name=name() as all as all other properties defined within the enum.
* If false, an Enum is serialized as a name=value pair (name=name()) * * @param enumAsBean true to serialize an enum as a bean instead of as a name=value * pair (default=false) */ public void setEnumAsBean(boolean enumAsBean) { this.enumAsBean = enumAsBean; } protected static class JSONAnnotationFinder { private boolean serialize = true; private Method accessor; private String name; public JSONAnnotationFinder(Method accessor) { this.accessor = accessor; } public boolean shouldSerialize() { return serialize; } public String getName() { return name; } public JSONAnnotationFinder invoke() { JSON json = accessor.getAnnotation(JSON.class); serialize = json.serialize(); if (serialize && json.name().length() > 0) { name = json.name(); } return this; } } }



 


你可能感兴趣的:(struts2)