自定义注解实例

1. dto枚举校验

@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = ValueOfEnumValidator.class)
public @interface ValueOfEnum {
    Class<? extends Enum<?>> enumClass();
    String message() default "ERROR_ENUM_TYPE";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

校验器(使用枚举值name集合):

public class ValueOfEnumValidator implements ConstraintValidator<ValueOfEnum, CharSequence> {
    private List<String> acceptedValues;

    @Override
    public void initialize(ValueOfEnum annotation) {
        acceptedValues = Stream.of(annotation.enumClass().getEnumConstants())
                .map(Enum::name)
                .collect(Collectors.toList());
    }

    @Override
    public boolean isValid(CharSequence value, ConstraintValidatorContext context) {
        if(Objects.isNull(value)) {
            return true;
        }
        return acceptedValues.contains(value.toString());
    }
}

2. 数字四舍五入

@Documented
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Round {
    int value() default 2;
}
@Aspect
@Component
public class RoundAspect {
    @Around("execution(public * com.freaxjj.*Service.*(..))")
    public Object format(ProceedingJoinPoint joinPoint) throws Throwable {
        Object result = joinPoint.proceed();
        //格式化数字
        this.formatNumber(result);
        return result;
    }

    /**
     * 格式化数字
     * @param result
     */
    public void formatNumber(Object result) {
        if (result instanceof Result) {
            Object data = ((Result)result).getData();
            if (Objects.isNull(data)) {
                return;
            }

            if (data instanceof List) {
                List items = (List) data;
                items.forEach(this::resolveNumber);
                return;
            }

            this.resolveNumber(data);
        }
    }

    /**
     * 四舍五入number
     * @param item
     */
    private void resolveNumber(Object item) {
        Class clazz = item.getClass();
        Field[] fields = clazz.getDeclaredFields();
        for(Field field : fields) {
            Round round = field.getAnnotation(Round.class);
            if(Objects.nonNull(round)) {
                try {
                    field.setAccessible(true);
                    Object fieldVal = field.get(item);
                    if(Objects.nonNull(fieldVal)) {
                        int scale = round.value();
                        BigDecimal roundedDecimal = new BigDecimal(String.valueOf(fieldVal)).setScale(scale, RoundingMode.HALF_UP);
                        if(fieldVal instanceof String) {
                            field.set(item, roundedDecimal.toString());
                        } else if(fieldVal instanceof BigDecimal) {
                            field.set(item, roundedDecimal);
                        } else if(fieldVal instanceof Double) {
                            field.set(item, roundedDecimal.doubleValue());
                        } else if(fieldVal instanceof Float) {
                            field.set(item, roundedDecimal.floatValue());
                        }
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

3. 忽略vo字段返回

背景是dubbo默认使用Hessian2序列化框架,没有提供类似@JsonIgnore的注解。在不改动序列化器的情况下,采用的临时方案。用到了asm生成class的工具(其实可以直接使用fastjson或Jackson提供的注解进行序列化成json串或JSONObjcet即可)。

@Documented
//用于类型上
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface JSONFieldIgnore {
    
}
@Aspect
@Component
public class JSONFieldIgnoreAspect {
    @Around("execution(public * com.freaxjj.*Service.*(..))")
    public Object format(ProceedingJoinPoint joinPoint) throws Throwable {
        Object proceed = joinPoint.proceed();
        this.ignoreField(proceed);
        return proceed;
    }

    /**
     * 移除字段
     * @param proceed
     */
    public void ignoreField(Object proceed) {
        if (proceed instanceof Result) {
            Result result = (Result)proceed;
            Object data = result.getData();
            if (Objects.nonNull(data)) {
                if (data instanceof List) {
                    List pojoList = (List) data;
                    List jsonObjs = (List) pojoList.stream().map(this::transform).collect(Collectors.toList());
                    result.setData(jsonObjs);
                    return;
                }

                Object jsonObject = transform(data);
                result.setData(jsonObject);
            }
        }
    }

    private Object transform(Object pojo) {
        JSONFieldIgnore jsonFieldIgnore = pojo.getClass().getAnnotation(JSONFieldIgnore.class);
        if(Objects.nonNull(jsonFieldIgnore)) {
            //这里可以直接返回json串或JSONObject(项目问题限制)
            String jsonString = JSON.toJSONString(pojo);
            //使用asm动态生成新的class
            Class ignoreFieldClass = ClassUtil.genIgnoreFieldClass(pojo.getClass());
            return JSON.parseObject(jsonString, ignoreFieldClass);
        }
        return pojo;
    }
}

ClassUtil:

public class ClassUtil {

    /**
     * asm生成忽略字段后新的class
     * @param clazz
     * @return
     */
    public static Class<?> genIgnoreFieldClass(Class<?> clazz) {
        String className = clazz.getSimpleName() + "IgnoreFields";
        Class<?> ignoreFieldClass = ByteClassLoader.getLoadedClass(className);
        if(Objects.nonNull(ignoreFieldClass)) {
            return ignoreFieldClass;
        }

        // 创建ClassWriter对象
        ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
        // 定义新类
        String owner = className.replace(".", "/");
        String superName = clazz.getSuperclass().getName().replace(".", "/");
        classWriter.visit(Opcodes.V17, Opcodes.ACC_PUBLIC, owner, null, superName, null);

        Field[] fields = clazz.getDeclaredFields();
        //生成成员变量
        FieldVisitor fv;
        for (Field field : fields) {
            if (!isIgnore(field)) {
                fv = classWriter.visitField(Opcodes.ACC_PRIVATE, field.getName(), getDescriptor(field), null, null);
                fv.visitEnd();
            }
        }

        // 创建构造函数
        MethodVisitor mvInit = classWriter.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
        // 调用超类的构造函数
        mvInit.visitVarInsn(Opcodes.ALOAD, 0);
        mvInit.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
        //构造函数返回
        mvInit.visitInsn(Opcodes.RETURN);
        mvInit.visitMaxs(1, 1);
        mvInit.visitEnd();

        // 创建get、set方法
        MethodVisitor mvGetter;
        MethodVisitor mvSetter;
        for (Field field : fields) {
            if (!isIgnore(field)) {
                mvGetter = classWriter.visitMethod(Opcodes.ACC_PUBLIC, "get" + capitalize(field.getName()), "()" + getDescriptor(field), null, null);
                mvGetter.visitCode();
                mvGetter.visitVarInsn(Opcodes.ALOAD, 0);
                mvGetter.visitFieldInsn(Opcodes.GETFIELD, owner, field.getName(), getDescriptor(field));
                mvGetter.visitInsn(getReturnOpcode(field.getType()));
                mvGetter.visitMaxs(1, 1);
                mvGetter.visitEnd();

                mvSetter = classWriter.visitMethod(Opcodes.ACC_PUBLIC, "set" + capitalize(field.getName()), "(" + getDescriptor(field) + ")V", null, null);
                mvSetter.visitCode();
                mvSetter.visitVarInsn(Opcodes.ALOAD, 0);
                mvSetter.visitVarInsn(Opcodes.ALOAD, 1);
                mvSetter.visitFieldInsn(Opcodes.PUTFIELD, owner, field.getName(), getDescriptor(field));
                mvSetter.visitInsn(Opcodes.RETURN);
                mvSetter.visitMaxs(2, 2);
                mvSetter.visitEnd();
            }
        }

        classWriter.visitEnd();
        // 加载新定义的类,并返回Class对象
        byte[] bytes = classWriter.toByteArray();
        return ByteClassLoader.getInstance().defineClass(className, bytes);
    }

    private static int getReturnOpcode(Class<?> type) {
        if (type == void.class) {
            return Opcodes.RETURN;
        } else if (type == byte.class || type == short.class || type == char.class || type == int.class || type == boolean.class) {
            return Opcodes.IRETURN;
        } else if (type == float.class) {
            return Opcodes.FRETURN;
        } else if (type == long.class) {
            return Opcodes.LRETURN;
        } else if (type == double.class) {
            return Opcodes.DRETURN;
        } else {
            return Opcodes.ARETURN;
        }
    }

    private static String getDescriptor(Field f) {
        if (f.getType() == byte.class) {
            return "B";
        } else if (f.getType() == short.class) {
            return "S";
        } else if (f.getType() == char.class) {
            return "C";
        } else if (f.getType() == int.class) {
            return "I";
        } else if (f.getType() == boolean.class) {
            return "Z";
        } else if (f.getType() == float.class) {
            return "F";
        } else if (f.getType() == long.class) {
            return "J";
        } else if (f.getType() == double.class) {
            return "D";
        } else {
            return "L" + f.getType().getName().replace(".", "/") + ";";
        }
    }

    private static String capitalize(String str) {
        return str.substring(0, 1).toUpperCase() + str.substring(1);
    }

    /**
     * 字段是否忽略
     * @param field
     * @return
     */
    private static boolean isIgnore(Field field) {
        JsonIgnore jsonIgnoreAnnotation = field.getAnnotation(JsonIgnore.class);
        JSONField ignoreAnnotation = field.getAnnotation(JSONField.class);
        return Objects.nonNull(jsonIgnoreAnnotation) || (Objects.nonNull(ignoreAnnotation) && !ignoreAnnotation.serialize());
    }
}

自定义类加载器(应该有封装好的类可以直接使用)

public class ByteClassLoader extends ClassLoader {
    private final static ByteClassLoader instance = new ByteClassLoader();

    public static ByteClassLoader getInstance() {
        return instance;
    }

    public Class<?> defineClass(String name, byte[] b) {
        return defineClass(name, b, 0, b.length);
    }

    public static Class<?> getLoadedClass(String className) {
        return instance.findLoadedClass(className);
    }
}

转载请标明原文链接:https://www.freaxjj.tk/zi-ding-yi-zhu-jie-shi-li/

comments powered by Disqus