做一个,可以传入对象,方法声明的形式校验参数非空,想要实现的效果如下
//user类:Long id,String name; User user = new User(1L,""); JsonUtils.validEmpty(user,User::getId,User::getName);
说一下思路
-
传入对象,方法声明(即对象方法),可以用到有来有回的函数接口 R apply(T t)。
-
函数接口可以获取的信息有:
- 传入的类型
- 传入的调用方法
- 对象对应方法的返回值
- 对象对应方法返回值类型
-
校验到非空字段后,需要知道这个字段代表什么意思,这里使用一个自定义注解,将此注解到对应字段上,里面的value就是字段含义
-
逻辑:
- 根据传入的对象user,获取到对象对应方法的值(apply函数接口特性)
- 根据获取的值做非空校验,获取到为空的字段
- 获取字段Field类信息(知道 Class对象,调用方法)
- 获取字段的注解value
- 返回为空的字段信息。
import com.cuihq.testdemo.annotation.CommentTarget; import org.apache.commons.lang3.StringUtils; import java.io.Serializable; import java.lang.invoke.SerializedLambda; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Optional; //函数式接口注解 @FunctionalInterface public interface SFunction二、自定义注解extends Serializable { R apply(T t); default SerializedLambda getSerializedLambda() throws Exception { //writeReplace改了好像会报异常 Method write = this.getClass().getDeclaredMethod("writeReplace"); write.setAccessible(true); return (SerializedLambda) write.invoke(this); } default String getImplClass() { try { //这里拿到的数据是com/cuihq/。。。 //需要将 /转换成. 利用Class.forName才会生效 String implClass = getSerializedLambda().getImplClass(); String result = implClass.replace("/", "."); return result; } catch (Exception e) { return null; } } default String getImplMethodName() { try { return getSerializedLambda().getImplMethodName(); } catch (Exception e) { return null; } } default String getFieldName(){ String methodName = this.getImplMethodName(); String valueTmp = StringUtils .removeStartIgnoreCase(methodName, "get"); String valuePre = valueTmp.substring(0, 1); String valueSux = valueTmp.substring(1); return valuePre.toLowerCase() + valueSux; } default String getCommentValue(){ String fieldName = this.getFieldName(); String implClass = this.getImplClass(); Field f = null; try { f = getField(Class.forName(implClass), fieldName); } catch (ClassNotFoundException e) { e.printStackTrace(); } CommentTarget commentTarget = null; if(f!=null){ commentTarget = f.getAnnotation(CommentTarget.class); } return commentTarget==null ? "": commentTarget.value(); } default Field getField( Class> c, String FieldName) { try { Field f = c.getDeclaredField(FieldName); return f; } catch (NoSuchFieldException e) { if (c.getSuperclass() == null){ return null; } else{ return getField( c.getSuperclass(), FieldName); } } catch (Exception ex) { return null; } } }
package com.cuihq.testdemo.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface CommentTarget {
String value() default "";
}
三、工具类方法
static四、单元测试void validEmpty(Object obj, SFunction ... functions){ String msg = Stream.of(functions) .filter(x -> isAnyoneEmpty(x.apply((T) obj))) .map(fun -> String.format("【%s】不能为空", fun.getCommentValue())) .collect(Collectors.joining(",")); System.out.println(msg); } private static boolean isAnyoneEmpty(Object obj) { if (obj == null) { return obj == null; } else if (obj instanceof Collection>) { return ((Collection>) obj).isEmpty(); } else if (obj instanceof String) { return obj.toString().length() == 0; } else if (obj.getClass().isArray()) { return ((Object[]) obj).length == 0; } else if (obj instanceof Map) { return ((Map, ?>) obj).isEmpty(); } else if (obj instanceof StringBuffer) { return ((StringBuffer) obj).length() == 0; } else if (obj instanceof StringBuilder) { return ((StringBuilder) obj).length() == 0; } return false; }
@Test
public void validEmptyTest() {
User user = new User(1L,"");
JsonUtils.validEmpty(user,User::getId,User::getName);
}
输出结果
【自定义name】不能为空



