Created
December 29, 2015 10:38
-
-
Save fivesmallq/af9296046f2c62013274 to your computer and use it in GitHub Desktop.
重现 fastjson filter bug
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.alibaba.fastjson.JSON; | |
import com.alibaba.fastjson.parser.deserializer.ExtraProcessor; | |
import com.alibaba.fastjson.serializer.NameFilter; | |
import com.alibaba.fastjson.serializer.SerializerFeature; | |
import org.apache.commons.lang3.Validate; | |
import java.lang.reflect.Field; | |
import java.lang.reflect.Modifier; | |
/** | |
* @author <a href="mailto:[email protected]">wuzhiqiang</a> | |
* @version Revision: 1.0 | |
* @date 15/12/23 下午3:19 | |
*/ | |
public class StringUtils { | |
/** | |
* Convert a name in camelCase to an underscored name in upper case. Any | |
* upper case letters are converted to lower case with a preceding | |
* underscore. | |
* <p> | |
* 主要的作用是把java的字段转化为数据库字段.数字会被当成一个大写字母,在前面添加下划线,<br> | |
* 如果连续两个字符都是数字,会当成一个整体.处理完毕后会返回小写格式 | |
* | |
* <pre> | |
* StringUtils.underscore("userNameLast10") = "update_name_last_10"; | |
* StringUtils.underscore("xx2") = "xx_2"; | |
* </pre> | |
* | |
* @param name | |
* the string containing original name | |
* @return the converted name toLowerCase | |
*/ | |
public static String underscore(String name) { | |
StringBuilder result = new StringBuilder(); | |
if (name != null && name.length() > 0) { | |
result.append(name.substring(0, 1).toLowerCase()); | |
for (int i = 1; i < name.length(); i++) { | |
String s = name.substring(i, i + 1); | |
String b = name.substring(i - 1, i); | |
// 如果这个字符是大写,或者前一个字符不是数字,那么添加一个下划线 | |
if (s.equals(s.toUpperCase()) && !Character.isDigit(b.charAt(0))) { | |
result.append('_'); | |
result.append(s); | |
} else { | |
result.append(s); | |
} | |
} | |
} | |
return result.toString().toLowerCase(); | |
} | |
/** | |
* 和underscore相反,这个方法用来把数据库字段转化为java字段 | |
* | |
* <pre> | |
* StringUtils.camelcase("user_name_last") = "userNameLast"; | |
* StringUtils.camelcase("USER") = "user"; | |
* </pre> | |
* | |
* @see StringUtils#underscore(String) | |
* @param name | |
* @return | |
*/ | |
public static String camelcase(String name) { | |
StringBuilder result = new StringBuilder(); | |
boolean nextIsUpper = false; | |
if (name != null && name.length() > 0) { | |
if (name.length() > 1 && name.substring(1, 2).equals("_")) { | |
result.append(name.substring(0, 1).toUpperCase()); | |
} else { | |
result.append(name.substring(0, 1).toLowerCase()); | |
} | |
for (int i = 1; i < name.length(); i++) { | |
String s = name.substring(i, i + 1); | |
if (s.equals("_")) { | |
nextIsUpper = true; | |
} else { | |
if (nextIsUpper) { | |
result.append(s.toUpperCase()); | |
nextIsUpper = false; | |
} else { | |
result.append(s.toLowerCase()); | |
} | |
} | |
} | |
} | |
return result.toString(); | |
} | |
public static void main(String[] args) { | |
//序列化通过 NameFilter 来处理 | |
NameFilter underscoreFilter=new NameFilter() { | |
@Override | |
public String process(Object object, String name, Object value) { | |
return underscore(name); | |
} | |
}; | |
Vo vo=new Vo(); | |
vo.setMpsRegistrationRecord("value1"); | |
vo.setIntellectualPropertyPledge("value2"); | |
//使用 filter,WriteMapNullValue不生效 | |
String json= JSON.toJSONString(vo,underscoreFilter, SerializerFeature.PrettyFormat,SerializerFeature.WriteMapNullValue,SerializerFeature.WriteNullStringAsEmpty); | |
System.out.println("设置了 filter 和 WriteMapNullValue\n"+json); | |
//不使用 filter,WriteMapNullValue生效 | |
String json2= JSON.toJSONString(vo, SerializerFeature.PrettyFormat,SerializerFeature.WriteMapNullValue,SerializerFeature.WriteNullStringAsEmpty); | |
System.out.println("不设置filter 只设置WriteMapNullValue\n"+json2); | |
//反序列化通过processor 处理 | |
ExtraProcessor processor = new ExtraProcessor() { | |
public void processExtra(Object object, String key, Object value) { | |
String camelKey=camelcase(key); | |
setFieldValue(object,camelKey,value); | |
} | |
}; | |
Vo tmp=JSON.parseObject(json,Vo.class,processor); | |
System.out.println(tmp.getMpsRegistrationRecord()); | |
System.out.println(tmp.getIntellectualPropertyPledge()); | |
} | |
/** | |
* 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数. | |
*/ | |
public static void setFieldValue(final Object obj, final String fieldName, | |
final Object value) { | |
Field field = getAccessibleField(obj, fieldName); | |
if (field == null) { | |
throw new IllegalArgumentException("Could not find field [" | |
+ fieldName + "] on target [" + obj + "]"); | |
} | |
try { | |
field.set(obj, value); | |
} catch (IllegalAccessException e) { | |
//eat it | |
} | |
} | |
/** | |
* 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问. | |
* <p> | |
* 如向上转型到Object仍无法找到, 返回null. | |
*/ | |
public static Field getAccessibleField(final Object obj, | |
final String fieldName) { | |
Validate.notNull(obj, "object can't be null"); | |
Validate.notNull(fieldName, "fieldName can't be blank"); | |
for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass | |
.getSuperclass()) { | |
try { | |
Field field = superClass.getDeclaredField(fieldName); | |
makeAccessible(field); | |
return field; | |
} catch (NoSuchFieldException e) {// NOSONAR | |
// Field不在当前类定义,继续向上转型 | |
} | |
} | |
return null; | |
} | |
/** | |
* 改变private/protected的成员变量为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。 | |
*/ | |
public static void makeAccessible(Field field) { | |
if ((!Modifier.isPublic(field.getModifiers()) | |
|| !Modifier.isPublic(field.getDeclaringClass().getModifiers()) || Modifier | |
.isFinal(field.getModifiers())) && !field.isAccessible()) { | |
field.setAccessible(true); | |
} | |
} | |
static class Vo{ | |
private String mpsRegistrationRecord; | |
private String intellectualPropertyPledge; | |
private String testStringNullAsEmpty; | |
public String getMpsRegistrationRecord() { | |
return mpsRegistrationRecord; | |
} | |
public void setMpsRegistrationRecord(String mpsRegistrationRecord) { | |
this.mpsRegistrationRecord = mpsRegistrationRecord; | |
} | |
public String getIntellectualPropertyPledge() { | |
return intellectualPropertyPledge; | |
} | |
public void setIntellectualPropertyPledge(String intellectualPropertyPledge) { | |
this.intellectualPropertyPledge = intellectualPropertyPledge; | |
} | |
public String getTestStringNullAsEmpty() { | |
return testStringNullAsEmpty; | |
} | |
public void setTestStringNullAsEmpty(String testStringNullAsEmpty) { | |
this.testStringNullAsEmpty = testStringNullAsEmpty; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment