Skip to content

Instantly share code, notes, and snippets.

@fivesmallq
Created December 29, 2015 10:38
Show Gist options
  • Save fivesmallq/af9296046f2c62013274 to your computer and use it in GitHub Desktop.
Save fivesmallq/af9296046f2c62013274 to your computer and use it in GitHub Desktop.
重现 fastjson filter bug
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:wuzhiqiang@ucfgroup.com">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(&quot;userNameLast10&quot;) = &quot;update_name_last_10&quot;;
* StringUtils.underscore(&quot;xx2&quot;) = &quot;xx_2&quot;;
* </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(&quot;user_name_last&quot;) = &quot;userNameLast&quot;;
* StringUtils.camelcase(&quot;USER&quot;) = &quot;user&quot;;
* </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