From 7f0b07922d3b9a82b96190c41fcee0da9ffd8c59 Mon Sep 17 00:00:00 2001 From: lijiahong Date: Wed, 7 Jul 2021 18:50:15 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E9=80=92=E5=BD=92=E6=B7=B1?= =?UTF-8?q?=E5=BA=A6=E9=85=8D=E7=BD=AE=EF=BC=8C=E4=BF=AE=E5=A4=8D=E5=A4=9A?= =?UTF-8?q?=E5=B1=82=E7=BA=A7=E6=95=B0=E6=8D=AE=E8=BF=94=E5=9B=9E=E4=B8=8D?= =?UTF-8?q?=E5=AE=8C=E5=85=A8=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/io/jboot/web/json/JbootJson.java | 426 +++++++++--------- .../io/jboot/web/json/JbootJsonConfig.java | 171 +++---- 2 files changed, 303 insertions(+), 294 deletions(-) diff --git a/src/main/java/io/jboot/web/json/JbootJson.java b/src/main/java/io/jboot/web/json/JbootJson.java index 5bd8a93a..7b506773 100644 --- a/src/main/java/io/jboot/web/json/JbootJson.java +++ b/src/main/java/io/jboot/web/json/JbootJson.java @@ -1,213 +1,213 @@ -/** - * Copyright (c) 2015-2021, Michael Yang 杨福海 (fuhai999@gmail.com). - *

- * 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 io.jboot.web.json; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.annotation.JSONField; -import com.jfinal.json.JFinalJson; -import com.jfinal.json.JFinalJsonKit; -import com.jfinal.kit.LogKit; -import com.jfinal.kit.StrKit; -import com.jfinal.plugin.activerecord.CPI; -import com.jfinal.plugin.activerecord.Model; -import io.jboot.Jboot; -import io.jboot.utils.ClassUtil; -import io.jboot.utils.StrUtil; - -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.*; - - -public class JbootJson extends JFinalJson { - - private JbootJsonConfig config = Jboot.config(JbootJsonConfig.class); - protected static Map, MethodsAndFieldsWrapper> methodAndFieldsCache = new HashMap<>(); - - public JbootJson() { - - //跳过 null 值输出到浏览器,提高传输性能 - setSkipNullValueField(config.isSkipNullValueField()); - - //设置转换层级 - setConvertDepth(8); - - //默认设置为 CamelCase 的属性模式 - if (config.isCamelCaseJsonStyleEnable()) { - setModelAndRecordFieldNameConverter((fieldName) -> StrKit.toCamelCase(fieldName, config.isCamelCaseToLowerCaseAnyway())); - } - - setToJsonFactory(o -> o instanceof Model ? jbootModelToJson : null); - - if (StrUtil.isNotBlank(config.getTimestampPattern())) { - setTimestampPattern(config.getTimestampPattern()); - } - } - - - protected JFinalJsonKit.ToJson> jbootModelToJson = (model, depth, ret) -> { - if (JFinalJsonKit.checkDepth(depth--, ret)) { - return; - } - - Map map = new HashMap<>(); - - if (!config.isSkipModelAttrs()) { - fillModelAttrsToMap(CPI.getAttrs(model), map); - } - - if (!config.isSkipBeanGetters()) { - fillBeanToMap(model, map); - } - - optimizeMapAttrs(map); - - JFinalJsonKit.mapToJson(map, depth, ret); - }; - - - protected void fillModelAttrsToMap(Map attrs, Map toMap) { - if (attrs != null && !attrs.isEmpty()) { - for (Map.Entry entry : attrs.entrySet()) { - String fieldName = entry.getKey(); - if (config.isCamelCaseJsonStyleEnable()) { - fieldName = StrKit.toCamelCase(fieldName, config.isCamelCaseToLowerCaseAnyway()); - } - toMap.put(fieldName, entry.getValue()); - } - } - } - - - protected void fillBeanToMap(Object bean, Map toMap) { - - MethodsAndFieldsWrapper wrapper = methodAndFieldsCache.get(bean.getClass()); - if (wrapper == null) { - synchronized (this) { - if (wrapper == null) { - wrapper = new MethodsAndFieldsWrapper(bean.getClass()); - } else { - wrapper = methodAndFieldsCache.get(bean.getClass()); - } - } - } - - for (String ignoreField : wrapper.ignoreFields) { - toMap.remove(ignoreField); - } - - - for (int i = 0; i < wrapper.fields.size(); i++) { - String originalField = wrapper.originalFields.get(i); - toMap.remove(originalField); - - Object value = invokeMethod(wrapper.methods.get(i), bean); - String field = wrapper.fields.get(i); - toMap.put(field, value); - } - - } - - - protected void optimizeMapAttrs(Map map) { - } - - protected Object invokeMethod(Method method, Object bean) { - try { - return method.invoke(bean); - } catch (Exception ex) { - LogKit.error("can not invoke method: " + ClassUtil.buildMethodString(method), ex); - return null; - } - } - - - @Override - public T parse(String jsonString, Class type) { - return JSON.parseObject(jsonString, type); - } - - - public static class MethodsAndFieldsWrapper { - - - private static boolean hasFastJson = ClassUtil.hasClass("com.alibaba.fastjson.JSON"); - - private List fields = new LinkedList<>(); - private List methods = new LinkedList<>(); - private List originalFields = new LinkedList<>(); - - //需要忽略的字段 - private List ignoreFields = new ArrayList<>(); - - public MethodsAndFieldsWrapper(Class reflectiveClass) { - - Method[] methodArray = reflectiveClass.getMethods(); - for (Method method : methodArray) { - if (method.getParameterCount() != 0 - || method.getReturnType() == void.class - || !Modifier.isPublic(method.getModifiers()) - || "getClass".equals(method.getName())) { - continue; - } - - - String fieldName = getGetterMethodField(method.getName()); - if (fieldName != null) { - String attrName = StrKit.firstCharToLowerCase(fieldName); - if (isIgnoreFiled(method)) { - ignoreFields.add(attrName); - } else { - originalFields.add(attrName); - fields.add(getDefineName(method, attrName)); - methods.add(method); - } - } - - } - } - - private String getGetterMethodField(String methodName) { - if (methodName.startsWith("get") && methodName.length() > 3) { - return methodName.substring(3); - } else if (methodName.startsWith("is") && methodName.length() > 2) { - return methodName.substring(2); - } - return null; - } - - - private String getDefineName(Method method, String orginalName) { - if (hasFastJson) { - JSONField jsonField = method.getAnnotation(JSONField.class); - if (jsonField != null && StrUtil.isNotBlank(jsonField.name())) { - return jsonField.name(); - } - } - return orginalName; - } - - private boolean isIgnoreFiled(Method method) { - if (hasFastJson) { - JSONField jsonField = method.getAnnotation(JSONField.class); - if (jsonField != null && !jsonField.serialize()) { - return true; - } - } - return method.getAnnotation(JsonIgnore.class) != null; - } - } -} +/** + * Copyright (c) 2015-2021, Michael Yang 杨福海 (fuhai999@gmail.com). + *

+ * 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 io.jboot.web.json; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.annotation.JSONField; +import com.jfinal.json.JFinalJson; +import com.jfinal.json.JFinalJsonKit; +import com.jfinal.kit.LogKit; +import com.jfinal.kit.StrKit; +import com.jfinal.plugin.activerecord.CPI; +import com.jfinal.plugin.activerecord.Model; +import io.jboot.Jboot; +import io.jboot.utils.ClassUtil; +import io.jboot.utils.StrUtil; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.*; + + +public class JbootJson extends JFinalJson { + + private JbootJsonConfig config = Jboot.config(JbootJsonConfig.class); + protected static Map, MethodsAndFieldsWrapper> methodAndFieldsCache = new HashMap<>(); + + public JbootJson() { + + //跳过 null 值输出到浏览器,提高传输性能 + setSkipNullValueField(config.isSkipNullValueField()); + + //设置转换层级 + setConvertDepth(config.getDepth()); + + //默认设置为 CamelCase 的属性模式 + if (config.isCamelCaseJsonStyleEnable()) { + setModelAndRecordFieldNameConverter((fieldName) -> StrKit.toCamelCase(fieldName, config.isCamelCaseToLowerCaseAnyway())); + } + + setToJsonFactory(o -> o instanceof Model ? jbootModelToJson : null); + + if (StrUtil.isNotBlank(config.getTimestampPattern())) { + setTimestampPattern(config.getTimestampPattern()); + } + } + + + protected JFinalJsonKit.ToJson> jbootModelToJson = (model, depth, ret) -> { + if (JFinalJsonKit.checkDepth(depth--, ret)) { + return; + } + + Map map = new HashMap<>(); + + if (!config.isSkipModelAttrs()) { + fillModelAttrsToMap(CPI.getAttrs(model), map); + } + + if (!config.isSkipBeanGetters()) { + fillBeanToMap(model, map); + } + + optimizeMapAttrs(map); + + JFinalJsonKit.mapToJson(map, depth, ret); + }; + + + protected void fillModelAttrsToMap(Map attrs, Map toMap) { + if (attrs != null && !attrs.isEmpty()) { + for (Map.Entry entry : attrs.entrySet()) { + String fieldName = entry.getKey(); + if (config.isCamelCaseJsonStyleEnable()) { + fieldName = StrKit.toCamelCase(fieldName, config.isCamelCaseToLowerCaseAnyway()); + } + toMap.put(fieldName, entry.getValue()); + } + } + } + + + protected void fillBeanToMap(Object bean, Map toMap) { + + MethodsAndFieldsWrapper wrapper = methodAndFieldsCache.get(bean.getClass()); + if (wrapper == null) { + synchronized (this) { + if (wrapper == null) { + wrapper = new MethodsAndFieldsWrapper(bean.getClass()); + } else { + wrapper = methodAndFieldsCache.get(bean.getClass()); + } + } + } + + for (String ignoreField : wrapper.ignoreFields) { + toMap.remove(ignoreField); + } + + + for (int i = 0; i < wrapper.fields.size(); i++) { + String originalField = wrapper.originalFields.get(i); + toMap.remove(originalField); + + Object value = invokeMethod(wrapper.methods.get(i), bean); + String field = wrapper.fields.get(i); + toMap.put(field, value); + } + + } + + + protected void optimizeMapAttrs(Map map) { + } + + protected Object invokeMethod(Method method, Object bean) { + try { + return method.invoke(bean); + } catch (Exception ex) { + LogKit.error("can not invoke method: " + ClassUtil.buildMethodString(method), ex); + return null; + } + } + + + @Override + public T parse(String jsonString, Class type) { + return JSON.parseObject(jsonString, type); + } + + + public static class MethodsAndFieldsWrapper { + + + private static boolean hasFastJson = ClassUtil.hasClass("com.alibaba.fastjson.JSON"); + + private List fields = new LinkedList<>(); + private List methods = new LinkedList<>(); + private List originalFields = new LinkedList<>(); + + //需要忽略的字段 + private List ignoreFields = new ArrayList<>(); + + public MethodsAndFieldsWrapper(Class reflectiveClass) { + + Method[] methodArray = reflectiveClass.getMethods(); + for (Method method : methodArray) { + if (method.getParameterCount() != 0 + || method.getReturnType() == void.class + || !Modifier.isPublic(method.getModifiers()) + || "getClass".equals(method.getName())) { + continue; + } + + + String fieldName = getGetterMethodField(method.getName()); + if (fieldName != null) { + String attrName = StrKit.firstCharToLowerCase(fieldName); + if (isIgnoreFiled(method)) { + ignoreFields.add(attrName); + } else { + originalFields.add(attrName); + fields.add(getDefineName(method, attrName)); + methods.add(method); + } + } + + } + } + + private String getGetterMethodField(String methodName) { + if (methodName.startsWith("get") && methodName.length() > 3) { + return methodName.substring(3); + } else if (methodName.startsWith("is") && methodName.length() > 2) { + return methodName.substring(2); + } + return null; + } + + + private String getDefineName(Method method, String orginalName) { + if (hasFastJson) { + JSONField jsonField = method.getAnnotation(JSONField.class); + if (jsonField != null && StrUtil.isNotBlank(jsonField.name())) { + return jsonField.name(); + } + } + return orginalName; + } + + private boolean isIgnoreFiled(Method method) { + if (hasFastJson) { + JSONField jsonField = method.getAnnotation(JSONField.class); + if (jsonField != null && !jsonField.serialize()) { + return true; + } + } + return method.getAnnotation(JsonIgnore.class) != null; + } + } +} diff --git a/src/main/java/io/jboot/web/json/JbootJsonConfig.java b/src/main/java/io/jboot/web/json/JbootJsonConfig.java index 521f5d79..9c137e18 100644 --- a/src/main/java/io/jboot/web/json/JbootJsonConfig.java +++ b/src/main/java/io/jboot/web/json/JbootJsonConfig.java @@ -1,81 +1,90 @@ -/** - * Copyright (c) 2015-2021, Michael Yang 杨福海 (fuhai999@gmail.com). - *

- * 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 io.jboot.web.json; - -import io.jboot.app.config.annotation.ConfigModel; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - */ -@ConfigModel(prefix = "jboot.json") -public class JbootJsonConfig { - - private boolean camelCaseJsonStyleEnable = true; - private boolean camelCaseToLowerCaseAnyway = false; - private boolean skipNullValueField = true; - private boolean skipModelAttrs = false; - private boolean skipBeanGetters = false; - private String timestampPattern; - - public boolean isCamelCaseJsonStyleEnable() { - return camelCaseJsonStyleEnable; - } - - public void setCamelCaseJsonStyleEnable(boolean camelCaseJsonStyleEnable) { - this.camelCaseJsonStyleEnable = camelCaseJsonStyleEnable; - } - - public boolean isCamelCaseToLowerCaseAnyway() { - return camelCaseToLowerCaseAnyway; - } - - public void setCamelCaseToLowerCaseAnyway(boolean camelCaseToLowerCaseAnyway) { - this.camelCaseToLowerCaseAnyway = camelCaseToLowerCaseAnyway; - } - - public boolean isSkipNullValueField() { - return skipNullValueField; - } - - public void setSkipNullValueField(boolean skipNullValueField) { - this.skipNullValueField = skipNullValueField; - } - - public boolean isSkipModelAttrs() { - return skipModelAttrs; - } - - public void setSkipModelAttrs(boolean skipModelAttrs) { - this.skipModelAttrs = skipModelAttrs; - } - - public boolean isSkipBeanGetters() { - return skipBeanGetters; - } - - public void setSkipBeanGetters(boolean skipBeanGetters) { - this.skipBeanGetters = skipBeanGetters; - } - - public String getTimestampPattern() { - return timestampPattern; - } - - public void setTimestampPattern(String timestampPattern) { - this.timestampPattern = timestampPattern; - } -} +/** + * Copyright (c) 2015-2021, Michael Yang 杨福海 (fuhai999@gmail.com). + *

+ * 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 io.jboot.web.json; + +import io.jboot.app.config.annotation.ConfigModel; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + */ +@ConfigModel(prefix = "jboot.json") +public class JbootJsonConfig { + + private boolean camelCaseJsonStyleEnable = true; + private boolean camelCaseToLowerCaseAnyway = false; + private boolean skipNullValueField = true; + private boolean skipModelAttrs = false; + private boolean skipBeanGetters = false; + private String timestampPattern; + private int depth = 16; + + public boolean isCamelCaseJsonStyleEnable() { + return camelCaseJsonStyleEnable; + } + + public void setCamelCaseJsonStyleEnable(boolean camelCaseJsonStyleEnable) { + this.camelCaseJsonStyleEnable = camelCaseJsonStyleEnable; + } + + public boolean isCamelCaseToLowerCaseAnyway() { + return camelCaseToLowerCaseAnyway; + } + + public void setCamelCaseToLowerCaseAnyway(boolean camelCaseToLowerCaseAnyway) { + this.camelCaseToLowerCaseAnyway = camelCaseToLowerCaseAnyway; + } + + public boolean isSkipNullValueField() { + return skipNullValueField; + } + + public void setSkipNullValueField(boolean skipNullValueField) { + this.skipNullValueField = skipNullValueField; + } + + public boolean isSkipModelAttrs() { + return skipModelAttrs; + } + + public void setSkipModelAttrs(boolean skipModelAttrs) { + this.skipModelAttrs = skipModelAttrs; + } + + public boolean isSkipBeanGetters() { + return skipBeanGetters; + } + + public void setSkipBeanGetters(boolean skipBeanGetters) { + this.skipBeanGetters = skipBeanGetters; + } + + public String getTimestampPattern() { + return timestampPattern; + } + + public void setTimestampPattern(String timestampPattern) { + this.timestampPattern = timestampPattern; + } + + public int getDepth() { + return depth; + } + + public void setDepth(int depth) { + this.depth = depth; + } +} -- Gitee