背景介紹
在日常代碼中有時候近乎避免不了的使用魔法值,但是如果使用傳入方法這種方式可以極大的降低魔法值出現的頻率並且不用創建靜態值。該方法主要參考了mybatisPlus,並在此基礎上進行了擴展。
相關代碼
FnConverter
package com.example.demo.bean;
import com.example.demo.entity.ValidatedRequestVO;
/**
* @author seal [email protected]
* @description
* @date 7/12/2020 7:20 PM
*/
public class FnConverter<F, T> {
/**
* 傳入方法返回字段名
*
* @param fn 方法
* @return 字段名
* @author seal [email protected]
* @date 7/12/2020 7:32 PM
*/
public String fnToFieldName(IFn<F, T> fn) {
return Reflections.fnToFieldName(fn);
}
/**
* 傳入方法返回方法名
*
* @param fn 方法
* @return 方法名
* @author seal [email protected]
* @date 7/12/2020 7:32 PM
*/
public String fnToFnName(IFn<F, T> fn) {
return Reflections.fnToFnName(fn);
}
/**
* 傳入方法返回註解
*
* @param fn 方法
* @return mongo註解
* @author seal [email protected]
* @date 7/12/2020 7:32 PM
*/
public String fnToMongoName(IFn<F, T> fn) {
return Reflections.fnToMongoName(fn);
}
public static void main(String[] args) {
FnConverter<ValidatedRequestVO, Object> fnConverter = new FnConverter();
String fieldName = fnConverter.fnToFieldName(ValidatedRequestVO::getStr);
System.out.println("字段名:" + fieldName);
String fnName = fnConverter.fnToFnName(ValidatedRequestVO::getStr);
System.out.println("方法名:" + fnName);
FnConverter<String, Object> fnConverter2 = new FnConverter();
String fieldName2 = fnConverter2.fnToFieldName(new ValidatedRequestVO()::setStr);
System.out.println("字段名:" + fieldName2);
String fnName2 = fnConverter2.fnToFnName(new ValidatedRequestVO()::setStr);
System.out.println("方法名:" + fnName2);
FnConverter<ValidatedRequestVO, Object> fnConverter3 = new FnConverter();
String fieldName3 = fnConverter3.fnToMongoName(ValidatedRequestVO::getStartDate);
System.out.println("字段名:" + fieldName3);
}
}
IFn
package com.example.demo.bean;
import java.io.Serializable;
/**
* F 傳入類型,T返回類型
* @author seal
*/
@FunctionalInterface
public interface IFn<F, T> extends Serializable {
T apply(F source);
}
Reflections
package com.example.demo.bean;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.mongodb.core.mapping.Field;
import java.beans.Introspector;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Method;
/**
* 傳入方法後的實現邏輯
*
* @author seal [email protected]
* @date 7/12/2020 7:20 PM
*/
@Slf4j
public class Reflections {
private Reflections() {
}
public static String fnToFieldName(IFn fn) {
try {
Method method = fn.getClass().getDeclaredMethod("writeReplace");
method.setAccessible(Boolean.TRUE);
SerializedLambda serializedLambda = (SerializedLambda) method.invoke(fn);
String getter = serializedLambda.getImplMethodName();
String fieldName = "";
if (getter.startsWith("get")) {
fieldName = Introspector.decapitalize(getter.replace("get", ""));
} else {
fieldName = Introspector.decapitalize(getter.replace("set", ""));
}
return fieldName;
} catch (ReflectiveOperationException e) {
log.warn(String.format("%s:%s",
Thread.currentThread().getStackTrace()[1].getMethodName(), e.getMessage()), e);
}
return "";
}
public static String fnToFnName(IFn fn) {
try {
Method method = fn.getClass().getDeclaredMethod("writeReplace");
method.setAccessible(Boolean.TRUE);
SerializedLambda serializedLambda = (SerializedLambda) method.invoke(fn);
return serializedLambda.getImplMethodName();
} catch (ReflectiveOperationException e) {
log.warn(String.format("%s:%s",
Thread.currentThread().getStackTrace()[1].getMethodName(), e.getMessage()), e);
}
return "";
}
public static String fnToMongoName(IFn fn) {
try {
Method method = fn.getClass().getDeclaredMethod("writeReplace");
method.setAccessible(Boolean.TRUE);
SerializedLambda serializedLambda = (SerializedLambda) method.invoke(fn);
String getter = serializedLambda.getImplMethodName();
String fieldName = "";
if (getter.startsWith("get")) {
fieldName = Introspector.decapitalize(getter.replace("get", ""));
} else {
fieldName = Introspector.decapitalize(getter.replace("set", ""));
}
Field field = Class.forName(serializedLambda.getImplClass().replace("/", ".")).getDeclaredField(fieldName).getAnnotation(Field.class);
return field == null ? fieldName : field.value();
} catch (ReflectiveOperationException e) {
log.warn(String.format("%s:%s",
Thread.currentThread().getStackTrace()[1].getMethodName(), e.getMessage()), e);
}
return "";
}
}
舉例應用
- 如視頻中所展現的可以取方法/字段的註解
- 利用反射實現偽代理
- 最普遍的應用即mybatisPlus的應用,可以動態傳入需要的字段和不需要的字段而不用改動sql,以此優化性能