Java 实用工具类(支持接口转Map)

背景:

在项目中web层->service->data层直接的交互是使用interface 作为参数进行传递,但是有多数地方需要对interface 数据进行转换,Java本身不支持接口转Map,故记录下此工具类


简介:

一个实用的工具类,用于将Java对象(尤其是命令对象,即符合Java Bean规范的对象)转换为Map<String, Object>。这个工具类通过反射获取对象的所有属性及其值

基本环境:JDK14以上


import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;


public abstract class CommandParameterUtils {

    public CommandParameterUtils() {
        throw new IllegalAccessError();
    }

    @SuppressWarnings("unchecked")
    public static Map<String, ?> getParameterMap(Object cmd) {
        if (null == cmd) {
            return Collections.emptyMap();
        }

        if (cmd instanceof Map<?, ?>) {
            return (Map<String, ?>) cmd;
        }

        Map<String, Object> parameterMap = (new HashMap<>());
        extractParameter(cmd, cmd.getClass(), parameterMap);
        return parameterMap;
    }

    private static void extractParameter(Object obj, Class<?> clazz, Map<String, Object> parameterMap) {
        if (null == clazz
                || Object.class.equals(clazz)
                || clazz.isArray()
                || clazz.isPrimitive()
                || clazz.isEnum()
                || Collection.class.isAssignableFrom(clazz)
                || Iterable.class.isAssignableFrom(clazz)) {
            return;
        }

        Arrays.stream(clazz.getDeclaredMethods())
                .map(ParameterNode::new)
                .filter(n -> n.canAccess(obj))
                .forEach(n -> {
                    String parameterName = n.getParameterName();
                    if (!parameterMap.containsKey(parameterName)) {
                        parameterMap.put(parameterName, n.getParameterValue(obj));
                    }
                });

        extractParameter(obj, clazz.getSuperclass(), parameterMap);
        for (Class<?> inf : clazz.getInterfaces()) {
            extractParameter(obj, inf, parameterMap);
        }
    }

    private record ParameterNode(Method method) {

        private boolean isReadOnly() {
            String name = method.getName();
            return (0 == method.getParameterCount() && (name.startsWith("get") || name.startsWith("is")));
        }

        boolean canAccess(Object obj) {
            if (!isReadOnly()) {
                return false;
            }
            try {
                return method.canAccess(obj);
            } catch (Exception ignore) {
                int modifier = method.getModifiers();
                return (Modifier.isPublic(modifier));
            }
        }

        String getParameterName() {
            String name = method.getName();
            if (name.startsWith("get")) {
                String pre = name.substring(0, 4);
                return name.replace(pre, pre.toLowerCase().substring(3));
            }

            if (name.startsWith("is")) {
                String pre = name.substring(0, 3);
                return name.replace(pre, pre.toLowerCase().substring(2));
            }

            return name;
        }

        Object getParameterValue(Object ins) {
            try {
                return method.invoke(ins);
            } catch (Exception cause) {
                throw (new IllegalStateException(cause));
            }
        }
    }
}

类及方法概述

  • CommandParameterUtils

    • 这是一个抽象类,目的是提供一个工具方法来转换对象为Map。
    • 构造函数是私有的,抛出异常,防止实例化。
  • 方法 getParameterMap(Object cmd)

    • 这是工具类的主方法,将对象转换为Map。
    • 如果传入的是null,返回空Map。
    • 如果传入的对象本身就是Map,直接返回。
    • 否则,创建一个新的Map,并调用extractParameter方法将对象的属性和值提取到Map中。
  • 方法 extractParameter(Object obj, Class<?> clazz, Map<String, Object> parameterMap)

    • 这是递归方法,用于遍历对象的所有类、父类和接口,提取它们的属性。
    • 忽略一些类型如数组、原始类型、枚举、集合和可迭代类型。
    • 遍历类的所有方法,利用ParameterNode类提取方法信息,并将属性和值存入Map中。
    • 递归调用以处理父类和接口的属性。
    • 内部类 ParameterNode

      这是一个记录类(Java 14引入的特性),用于封装方法,并提供一些便利方法来处理方法的属性。

    • 构造函数

      • ParameterNode(Method method):接受一个方法对象,创建一个新的节点。
    • 方法 isReadOnly

      • 检查方法是否为只读方法。只读方法是没有参数并且以"get"或"is"开头的方法。
    • 方法 canAccess

      • 检查方法是否可以访问。如果方法不是只读的,返回false
      • 尝试检查方法是否可以访问,并捕获可能的异常。如果方法可以访问,返回true。如果捕获到异常,则检查方法的修饰符是否为public
    • 方法 getParameterName

      • 获取属性名。方法名以"get"开头的属性名去掉"get"前缀并将首字母小写。以"is"开头的属性名去掉"is"前缀并将首字母小写。
    • 方法 getParameterValue

      • 调用方法获取属性值,并返回结果。如果调用方法时出现异常,抛出IllegalStateException

使用示例

public interface Command {
    String name();
}

public class cmd implements Command {
    private String name;

    public cmd(String name) {
        this.name= name;
    }

    @Override
    public String getName() {
        return name;
    }
}

使用CommandParameterUtils类将其转换为Map

public class Main {
    public static void main(String[] args) {
        Command command = new cmd("test");
        Map<String, ?> paramMap = CommandParameterUtils.getParameterMap(command);
        System.out.println(paramMap);
    }
}

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值