1、IGetter
import java.io.Serializable;
@FunctionalInterface
public interface IGetter<T> extends Serializable {
Object get(T source);
}
2、ISetter
import java.io.Serializable;
@FunctionalInterface
public interface ISetter<T, U> extends Serializable {
void set(T t, U u);
}
3、NjBeanUtils
import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import lombok.extern.slf4j.Slf4j;
/**
* @author : whp
* @describe :
* @date : 2022/6/29 9:53
*/
@Slf4j
public class NjBeanUtils extends BeanUtil {
/**
* list 列表之間的複製
* @param sources
* @param target
* @return
* @param <S>
* @param <T>
*/
public static <S, T> List<T> copyListProperties(List<S> sources, Supplier<T> target) {
if(CollUtil.isEmpty(sources)){
return null;
}
return copyListProperties(sources, target, null);
}
/**
* @author whp
* 使用場景:Entity、Bo、Vo層資料的複製,因為BeanUtils.copyProperties只能給目標物件的屬性賦值,卻不能在List集合下迴圈賦值,因此新增該方法
* 如:List<AdminEntity> 賦值到 List<AdminVo> ,List<AdminVo>中的 AdminVo 屬性都會被賦予到值
* S: 資料來源類 ,T: 目標類::new(eg: AdminVo::new)
*/
public static <S, T> List<T> copyListProperties(List<S> sources, Supplier<T> target, NjBeanUtilsCallBack<S, T> callBack) {
List<T> list = new ArrayList<>(sources.size());
for (S source : sources) {
T t = target.get();
copyProperties(source, t);
list.add(t);
if (callBack != null) {
// 回撥
callBack.callBack(source, t);
}
}
return list;
}
/**
* 透過getter的方法引用獲取欄位名
*/
public static <T> String convertToFieldName(IGetter<T> fn) {
try {
SerializedLambda lambda = getSerializedLambda(fn);
String methodName = lambda.getImplMethodName();
String prefix = null;
if (methodName.startsWith("get")) {
prefix = "get";
} else if (methodName.startsWith("is")) {
prefix = "is";
}
if (prefix == null) {
log.error("無效的getter方法: " + methodName);
}
return toLowerCaseFirstOne(methodName.replace(prefix, ""));
} catch (Exception e) {
log.error("透過getter的方法引用獲取欄位名失敗", e);
return null;
}
}
/**
* 透過setter的方法引用獲取欄位名
* @throws Exception
*/
public static <T, U> String convertToFieldName(ISetter<T, U> fn) {
try {
SerializedLambda lambda = getSerializedLambda(fn);
String methodName = lambda.getImplMethodName();
if (!methodName.startsWith("set")) {
log.error("無效的setter方法:" + methodName);
}
return toLowerCaseFirstOne(methodName.replace("set", ""));
} catch (Exception e) {
log.error("透過setter的方法引用獲取欄位名失敗", e);
return null;
}
}
/**
* 關鍵在於這個方法
*/
private static SerializedLambda getSerializedLambda(Serializable fn) throws Exception {
Method method = fn.getClass().getDeclaredMethod("writeReplace");
method.setAccessible(Boolean.TRUE);
SerializedLambda lambda = (SerializedLambda) method.invoke(fn);
return lambda;
}
/**
* 字串首字母轉小寫
*/
private static String toLowerCaseFirstOne(String field) {
if (Character.isLowerCase(field.charAt(0)))
return field;
else {
char firstOne = Character.toLowerCase(field.charAt(0));
String other = field.substring(1);
return new StringBuilder().append(firstOne).append(other).toString();
}
}
}
4、單元測試
public static void main(String[] args) {
System.out.println(NjBeanUtils.convertToFieldName(ShopIndex::getAddress));
System.out.println(NjBeanUtils.convertToFieldName(ShopIndex::getCityId));
System.out.println(NjBeanUtils.convertToFieldName(ShopIndex::setMartId));
System.out.println(NjBeanUtils.convertToFieldName(ShopIndex::setMartLocation));
}
5、執行結果
address
cityId
martId
martLocation