很小的项目中用了一下jfinal无奈不支持fastjson,传说中jfinal插件那么多,但是搜遍了地球也找不到与fastjson相关的,只看到http://www.oschina.net/question/272262_118711,就没有下文了(大概是jfinal想搞基让温少给写插件支持,而温少不鸟,搞基失败!),于是大神们都不解决只有靠自己动手,废话少说,先看治疗效果:
用上 JFinal 但是没有用上fastjson插件的的攻城狮近照
用上 JFinal 也用上了fastjson插件的的攻城狮近照
FastJsonActiveRecordPlugin:
package com.jfinal.ext.plugin; import javax.sql.DataSource; import com.alibaba.fastjson.parser.ParserConfig; import com.alibaba.fastjson.serializer.SerializeConfig; import com.alibaba.fastjson.serializer.SimpleDateFormatSerializer; import com.jfinal.ext.plugin.fastjson.ModelDeserializer; import com.jfinal.ext.plugin.fastjson.ModelSerializer; import com.jfinal.ext.plugin.fastjson.RecordSerializer; import com.jfinal.plugin.activerecord.ActiveRecordPlugin; import com.jfinal.plugin.activerecord.Config; import com.jfinal.plugin.activerecord.IDataSourceProvider; import com.jfinal.plugin.activerecord.Model; import com.jfinal.plugin.activerecord.Record; /** * FastJson ActiveRecordPlugin * * @author Obama * */ public class FastJsonActiveRecordPlugin extends ActiveRecordPlugin { public FastJsonActiveRecordPlugin(String configName, IDataSourceProvider dataSourceProvider, int transactionLevel) { super(configName, dataSourceProvider, transactionLevel); } public FastJsonActiveRecordPlugin(String configName, IDataSourceProvider dataSourceProvider) { super(configName, dataSourceProvider); } public FastJsonActiveRecordPlugin(String configName, DataSource dataSource, int transactionLevel) { super(configName, dataSource, transactionLevel); } public FastJsonActiveRecordPlugin(String configName, DataSource dataSource) { super(configName, dataSource); } public FastJsonActiveRecordPlugin(IDataSourceProvider dataSourceProvider, int transactionLevel) { super(dataSourceProvider, transactionLevel); } public FastJsonActiveRecordPlugin(IDataSourceProvider dataSourceProvider) { super(dataSourceProvider); } public FastJsonActiveRecordPlugin(DataSource dataSource, int transactionLevel) { super(dataSource, transactionLevel); } public FastJsonActiveRecordPlugin(DataSource dataSource) { super(dataSource); } public FastJsonActiveRecordPlugin(Config config) { super(config); } @Override public ActiveRecordPlugin addMapping(String tableName, String primaryKey, Class<? extends Model<?>> modelClass) { _fastJsonInit(modelClass); return super.addMapping(tableName, primaryKey, modelClass); } @Override public ActiveRecordPlugin addMapping(String tableName, Class<? extends Model<?>> modelClass) { _fastJsonInit(modelClass); return super.addMapping(tableName, modelClass); } private void _fastJsonInit(Class<? extends Model<?>> modelClass) { if (modelClass == Model.class) return; // 序列化 SerializeConfig.getGlobalInstance().put(modelClass, ModelSerializer.instance); // 反序列化 ParserConfig.getGlobalInstance().putDeserializer(modelClass, ModelDeserializer.instance); } @Override public boolean start() { boolean bol = super.start(); if (bol) { SerializeConfig.getGlobalInstance().put(Record.class, RecordSerializer.instance); // 时间格式 SerializeConfig.getGlobalInstance().put(java.sql.Timestamp.class, new SimpleDateFormatSerializer("yyyy-MM-dd HH:mm:ss")); } return bol; } }JfinalSerializer:
package com.jfinal.ext.plugin.fastjson; import java.io.IOException; import java.lang.reflect.Type; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.serializer.FilterUtils; import com.alibaba.fastjson.serializer.JSONSerializer; import com.alibaba.fastjson.serializer.NameFilter; import com.alibaba.fastjson.serializer.ObjectSerializer; import com.alibaba.fastjson.serializer.PropertyFilter; import com.alibaba.fastjson.serializer.PropertyPreFilter; import com.alibaba.fastjson.serializer.SerialContext; import com.alibaba.fastjson.serializer.SerializeWriter; import com.alibaba.fastjson.serializer.SerializerFeature; import com.alibaba.fastjson.serializer.ValueFilter; /** * FastJson JfinalSerializer * * @author Obama * */ public abstract class JfinalSerializer implements ObjectSerializer { protected abstract Map<String, Object> getMap(Object object); @SuppressWarnings({ "rawtypes", "unchecked" }) public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType) throws IOException { SerializeWriter out = serializer.getWriter(); Map<String, Object> map = null; if (object == null || (map = this.getMap(object)) == null) { out.writeNull(); return; } if (out.isEnabled(SerializerFeature.SortField)) { if ((!(map instanceof SortedMap)) && !(map instanceof LinkedHashMap)) { try { map = new TreeMap(map); } catch (Exception ex) { // skip } } } if (serializer.containsReference(object)) { serializer.writeReference(object); return; } SerialContext parent = serializer.getContext(); serializer.setContext(parent, object, fieldName); try { out.write('{'); serializer.incrementIndent(); Class<?> preClazz = null; ObjectSerializer preWriter = null; boolean first = true; if (out.isEnabled(SerializerFeature.WriteClassName)) { out.writeFieldName(JSON.DEFAULT_TYPE_KEY); out.writeString(object.getClass().getName()); first = false; } for (Map.Entry entry : map.entrySet()) { Object value = entry.getValue(); Object entryKey = entry.getKey(); { List<PropertyPreFilter> preFilters = serializer.getPropertyPreFiltersDirect(); if (preFilters != null && preFilters.size() > 0) { if (entryKey == null || entryKey instanceof String) { if (!FilterUtils.applyName(serializer, object, (String) entryKey)) { continue; } } else if (entryKey.getClass().isPrimitive() || entryKey instanceof Number) { String strKey = JSON.toJSONString(entryKey); if (!FilterUtils.applyName(serializer, object, strKey)) { continue; } } } } { List<PropertyFilter> propertyFilters = serializer.getPropertyFiltersDirect(); if (propertyFilters != null && propertyFilters.size() > 0) { if (entryKey == null || entryKey instanceof String) { if (!FilterUtils.apply(serializer, object, (String) entryKey, value)) { continue; } } else if (entryKey.getClass().isPrimitive() || entryKey instanceof Number) { String strKey = JSON.toJSONString(entryKey); if (!FilterUtils.apply(serializer, object, strKey, value)) { continue; } } } } { List<NameFilter> nameFilters = serializer.getNameFiltersDirect(); if (nameFilters != null && nameFilters.size() > 0) { if (entryKey == null || entryKey instanceof String) { entryKey = FilterUtils.processKey(serializer, object, (String) entryKey, value); } else if (entryKey.getClass().isPrimitive() || entryKey instanceof Number) { String strKey = JSON.toJSONString(entryKey); entryKey = FilterUtils.processKey(serializer, object, strKey, value); } } } { List<ValueFilter> valueFilters = serializer.getValueFiltersDirect(); if (valueFilters != null && valueFilters.size() > 0) { if (entryKey == null || entryKey instanceof String) { value = FilterUtils.processValue(serializer, object, (String) entryKey, value); } else if (entryKey.getClass().isPrimitive() || entryKey instanceof Number) { String strKey = JSON.toJSONString(entryKey); value = FilterUtils.processValue(serializer, object, strKey, value); } } } if (value == null) { if (!serializer.isEnabled(SerializerFeature.WriteMapNullValue)) { continue; } } if (entryKey instanceof String) { String key = (String) entryKey; if (!first) { out.write(','); } if (out.isEnabled(SerializerFeature.PrettyFormat)) { serializer.println(); } out.writeFieldName(key, true); } else { if (!first) { out.write(','); } if (out.isEnabled(SerializerFeature.BrowserCompatible) || out.isEnabled(SerializerFeature.WriteNonStringKeyAsString)) { String strEntryKey = JSON.toJSONString(entryKey); serializer.write(strEntryKey); } else { serializer.write(entryKey); } out.write(':'); } first = false; if (value == null) { out.writeNull(); continue; } Class<?> clazz = value.getClass(); if (clazz == preClazz) { preWriter.write(serializer, value, entryKey, null); } else { preClazz = clazz; preWriter = serializer.getObjectWriter(clazz); preWriter.write(serializer, value, entryKey, null); } } } finally { serializer.setContext(parent); } serializer.decrementIdent(); if (out.isEnabled(SerializerFeature.PrettyFormat) && map.size() > 0) { serializer.println(); } out.write('}'); } }ModelSerializer(支持model序列化):
package com.jfinal.ext.plugin.fastjson; import java.util.Map; import com.jfinal.plugin.activerecord.Model; /** * FastJson ModelSerializer * * @author Obama * */ public class ModelSerializer extends JfinalSerializer { public static ModelSerializer instance = new ModelSerializer(); @Override protected Map<String, Object> getMap(Object object) { return com.jfinal.plugin.activerecord.CPI.getAttrs((Model<?>) object); } }RecordSerializer(支持record序列化):
package com.jfinal.ext.plugin.fastjson; import java.util.Map; import com.jfinal.plugin.activerecord.Record; /** * FastJson RecordSerializer * * @author Obama * */ public class RecordSerializer extends JfinalSerializer { public static RecordSerializer instance = new RecordSerializer(); @Override protected Map<String, Object> getMap(Object object) { return ((Record) object).getColumns(); } }JsonFeildDes:
package com.jfinal.ext.plugin.fastjson; import java.lang.reflect.Field; import com.alibaba.fastjson.annotation.JSONField; /** * FastJson JsonFeildDes * * @author Obama * */ public class JsonFeildDes { private Field field; private JSONField jasonField; public JsonFeildDes(Field field, JSONField jasonField) { super(); this.field = field; this.jasonField = jasonField; } public Field getField() { return field; } public void setField(Field field) { this.field = field; } public JSONField getJasonField() { return jasonField; } public void setJasonField(JSONField jasonField) { this.jasonField = jasonField; } }ModelDeserializer(支持model反序列化):
package com.jfinal.ext.plugin.fastjson; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.util.HashMap; import java.util.Map; import com.alibaba.fastjson.JSONException; import com.alibaba.fastjson.annotation.JSONField; import com.alibaba.fastjson.parser.DefaultJSONParser; import com.alibaba.fastjson.parser.Feature; import com.alibaba.fastjson.parser.JSONLexer; import com.alibaba.fastjson.parser.JSONToken; import com.alibaba.fastjson.parser.ParseContext; import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer; import com.jfinal.plugin.activerecord.Model; import com.jfinal.plugin.activerecord.Table; import com.jfinal.plugin.activerecord.TableMapping; /** * FastJson ModelDeserializer * * @author Obama * */ public class ModelDeserializer implements ObjectDeserializer { public final static ModelDeserializer instance = new ModelDeserializer(); @SuppressWarnings("unchecked") public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) { final JSONLexer lexer = parser.getLexer(); if (lexer.token() == JSONToken.NULL) { lexer.nextToken(JSONToken.COMMA); return null; } T model = null; Map<String, Object> map = null; ParseContext context = parser.getContext(); Class<? extends Model<?>> clazz = null; Table table = null; Map<String, JsonFeildDes> jfd = null; try { clazz = (Class<? extends Model<?>>) type; table = TableMapping.me().getTable(clazz); jfd = new HashMap<String, JsonFeildDes>(); _scanJsonAnnotation(clazz, jfd); model = (T) clazz.newInstance(); map = com.jfinal.plugin.activerecord.CPI.getAttrs((Model<?>) model); parser.setContext(context, map, fieldName); deserialze(parser, fieldName, map, (Model<?>) model, jfd, table); return model; } catch (InstantiationException e) { throw new JSONException("init model exceptopn:" + e.getMessage()); } catch (IllegalAccessException e) { throw new JSONException("init model exceptopn:" + e.getMessage()); } catch (NumberFormatException e) { throw e; } finally { parser.setContext(context); clazz = null; table = null; jfd.clear(); } } private void _scanJsonAnnotation(Class<? extends Model<?>> clazz, Map<String, JsonFeildDes> jfd) { for (Field f : clazz.getDeclaredFields()) { if (Modifier.isStatic(f.getModifiers())) { continue; } JSONField jf = f.getAnnotation(JSONField.class); if (jf != null && jf.name() != null && jf.name().trim().length() != 0) { jfd.put(jf.name().trim(), new JsonFeildDes(f, jf)); } } } private <T> Map<String, Object> deserialze(DefaultJSONParser parser, Object fieldName, Map<String, Object> map, Model<?> model, Map<String, JsonFeildDes> jfd, Table table) throws NumberFormatException { JSONLexer lexer = parser.getLexer(); if (lexer.token() != JSONToken.LBRACE) { throw new JSONException("syntax error, expect {, actual " + lexer.token()); } ParseContext context = parser.getContext(); try { for (;;) { lexer.skipWhitespace(); char ch = lexer.getCurrent(); if (parser.isEnabled(Feature.AllowArbitraryCommas)) { while (ch == ',') { lexer.next(); lexer.skipWhitespace(); ch = lexer.getCurrent(); } } String key; if (ch == '"') { key = lexer.scanSymbol(parser.getSymbolTable(), '"'); lexer.skipWhitespace(); ch = lexer.getCurrent(); if (ch != ':') { throw new JSONException("expect ':' at " + lexer.pos()); } } else if (ch == '}') { lexer.next(); lexer.resetStringPosition(); lexer.nextToken(JSONToken.COMMA); return map; } else if (ch == '\'') { if (!parser.isEnabled(Feature.AllowSingleQuotes)) { throw new JSONException("syntax error"); } key = lexer.scanSymbol(parser.getSymbolTable(), '\''); lexer.skipWhitespace(); ch = lexer.getCurrent(); if (ch != ':') { throw new JSONException("expect ':' at " + lexer.pos()); } } else { if (!parser.isEnabled(Feature.AllowUnQuotedFieldNames)) { throw new JSONException("syntax error"); } key = lexer.scanSymbolUnQuoted(parser.getSymbolTable()); lexer.skipWhitespace(); ch = lexer.getCurrent(); if (ch != ':') { throw new JSONException("expect ':' at " + lexer.pos() + ", actual " + ch); } } lexer.next(); lexer.skipWhitespace(); ch = lexer.getCurrent(); lexer.resetStringPosition(); JsonFeildDes jsonfdes = null; Object value; lexer.nextToken(); int c = -1; if (lexer.token() == JSONToken.NULL) { value = null; lexer.nextToken(); } else { Type valueType = Object.class; if ((jsonfdes = jfd.get(key)) != null) { if (!jsonfdes.getJasonField().deserialize()) continue; valueType = jsonfdes.getField().getGenericType(); key = jsonfdes.getField().getName(); jsonfdes = null; } if (table.hasColumnLabel(key)) { c = 1; valueType = table.getColumnType(key); } value = parser.parseObject(valueType); valueType = null; } if (c == 1) { model.set(key, value); } else { model.put(key, value); } parser.checkMapResolve(map, key); parser.setContext(context, value, key); final int tok = lexer.token(); if (tok == JSONToken.EOF || tok == JSONToken.RBRACKET) { return map; } if (tok == JSONToken.RBRACE) { lexer.nextToken(); return map; } } } finally { parser.setContext(context); } } public int getFastMatchToken() { return JSONToken.LBRACE; } }
package com.jfinal.ext.render; import java.io.IOException; import java.io.PrintWriter; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import com.alibaba.fastjson.JSON; import com.jfinal.render.Render; import com.jfinal.render.RenderException; /** * FastJson JsonRender * * @author Obama * */ public class FastJsonRender extends Render { private static final long serialVersionUID = 3606364198859021837L; /** * http://zh.wikipedia.org/zh/MIME 在wiki中查到: * 尚未被接受为正式数据类型的subtype,可以使用x-开始的独立名称(例如application/x-gzip) 所以以下可能要改成 * application/x-json * * 通过使用firefox测试,struts2-json-plugin返回的是 application/json, 所以暂不改为 * application/x-json 1: 官方的 MIME type为application/json, 见 * http://en.wikipedia.org/wiki/MIME_type 2: IE 不支持 application/json, 在 ajax * 上传文件完成后返回 json时 IE 提示下载文件 */ private static final String contentType = "application/json;charset=" + getEncoding(); private static final String contentTypeForIE = "text/html;charset=" + getEncoding(); private boolean forIE = false; public FastJsonRender forIE() { forIE = true; return this; } private String jsonText; private String[] attrs; public FastJsonRender() { } @SuppressWarnings("serial") public FastJsonRender(final String key, final Object value) { if (key == null) throw new IllegalArgumentException("The parameter key can not be null."); this.jsonText = JSON.toJSONString(new HashMap<String, Object>() { { put(key, value); } }); } public FastJsonRender(String[] attrs) { if (attrs == null) throw new IllegalArgumentException("The parameter attrs can not be null."); this.attrs = attrs; } public FastJsonRender(String jsonText) { if (jsonText == null) throw new IllegalArgumentException("The parameter jsonString can not be null."); this.jsonText = jsonText; } public FastJsonRender(Object object) { if (object == null) throw new IllegalArgumentException("The parameter object can not be null."); this.jsonText = JSON.toJSONString(object); } public void render() { if (jsonText == null) buildJsonText(); PrintWriter writer = null; try { response.setHeader("Pragma", "no-cache"); // HTTP/1.0 caches might // not implement // Cache-Control and // might only implement // Pragma: no-cache response.setHeader("Cache-Control", "no-cache"); response.setDateHeader("Expires", 0); response.setContentType(forIE ? contentTypeForIE : contentType); writer = response.getWriter(); writer.write(jsonText); writer.flush(); } catch (IOException e) { throw new RenderException(e); } finally { if (writer != null) writer.close(); } } @SuppressWarnings({ "rawtypes", "unchecked" }) private void buildJsonText() { Map map = new HashMap(); if (attrs != null) { for (String key : attrs) map.put(key, request.getAttribute(key)); } else { Enumeration<String> attrs = request.getAttributeNames(); while (attrs.hasMoreElements()) { String key = attrs.nextElement(); Object value = request.getAttribute(key); map.put(key, value); } } this.jsonText = JSON.toJSONString(map); } }整合进jfinal很简单,只需要把ActiveRecordPlugin替换为FastJsonActiveRecordPlugin即可使用!
最后感谢OSC,感谢@wenshao !!感谢@JFinal ,感谢国家,感谢CCAV....