手写Java序列化工具

一、思考

假设给一个java bean,让你按照 json 的格式打印出来,你会怎么做?
比如这个java bean 长这样,并且创建了一个叫宝儿姐的朋友

package com.test;

public class User {

    private String name;
    private Integer age;
    private BigDecimal mony;
    private List<User> childs;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public BigDecimal getMony() {
        return mony;
    }

    public void setMony(BigDecimal mony) {
        this.mony = mony;
    }

    public List<User> getChilds() {
        return childs;
    }

    public void setChilds(List<User> childs) {
        this.childs = childs;
    }
}

public class JsonTest {
    
    public static void main(String[] args) throws Exception {
            User user = new User();
            user.setAge(18);
            user.setName("宝儿姐");
            user.setMony(new BigDecimal("-4000000.5"));
            List<User> userList = new ArrayList<>();
            User son = new User();
            son.setAge(1);
            son.setName("大壮");
            userList.add(son);
            User daughter = new User();
            daughter.setAge(10);
            daughter.setName("小美");
            userList.add(daughter);
    
            user.setChilds(userList);
    
            // 打印java bean
            printToJson(user);
            // 打印集合
            printToJson(userList);
            // 打印数值
            printToJson(new BigDecimal("1.235"));
            printToJson((byte)2);
            printToJson((short)3);
            printToJson(4);
            printToJson(5.1F);
            printToJson(5.2D);
            printToJson(233L);
            // 打印字符串
            printToJson("小美");
      }
    
    private static void printToJson(User user) {
        // .....
    }
}

我们调用 printToJson 之后,期望的输出是长这样的:

{"name":"宝儿姐","childs":[{"name":"大壮","age":1},{"name":"小美","age":10}],"age":18,"mony":-4000000.5}
[{"name":"大壮","age":1},{"name":"小美","age":10}]
1.235
2
3
4
5.1
5.2
233
"小美"

那么一个简单而又没啥设计的实现方式如下:

public class JsonTest {

    public static void main(String[] args) throws Exception {
        User user = new User();
        user.setAge(18);
        user.setName("宝儿姐");
        user.setMony(new BigDecimal("-4000000.5"));
        List<User> userList = new ArrayList<>();
        User son = new User();
        son.setAge(1);
        son.setName("大壮");
        userList.add(son);
        User daughter = new User();
        daughter.setAge(10);
        daughter.setName("小美");
        userList.add(daughter);

        user.setChilds(userList);

        // 打印java bean
        printToJson(user);
        // 打印集合
        printToJson(userList);
        // 打印数值
        printToJson(new BigDecimal("1.235"));
        printToJson((byte)2);
        printToJson((short)3);
        printToJson(4);
        printToJson(5.1F);
        printToJson(5.2D);
        printToJson(233L);
        // 打印字符串
        printToJson("小美");
    }

    private static <T> void printToJson(T obj) throws Exception {
        if (Objects.isNull(obj)) {
            System.out.println("");
            return;
        }

        Class<?> tClass = obj.getClass();
        StringWriter stringWriter = new StringWriter();
        if (tClass == String.class) {
            stringPrint(stringWriter, (String) obj);
        } else if (Number.class.isAssignableFrom(tClass)) {
            numberPrint(stringWriter, (Number) obj);
        } else if (Collection.class.isAssignableFrom(tClass)) {
            collectionPrint(stringWriter, (Collection) obj, null);
            // 省略数组,map等各种类型的打印
        } else {
            javaBeanPrint(stringWriter, obj, tClass);
        }

        System.out.println(stringWriter.toString());
    }

    private static void javaBeanPrint(StringWriter stringWriter, Object javaBean, Class<?> tClass) throws Exception {
        // 不考虑继承
        Method[] methods = tClass.getDeclaredMethods();
        if (Objects.isNull(methods) || methods.length == 0) {
            stringWriter.append("{}");
            return;
        }
        stringWriter.append("{");
        boolean hasPrev = false;
        for (Method method : methods) {
            String methodName = method.getName();
            if (methodName.startsWith("get") && methodName.length() > 3) {
                Object val = method.invoke(javaBean);
                if (Objects.isNull(val)) {
                    continue;
                }
                if (hasPrev) {
                    stringWriter.append(",");
                }
                String propertyName = methodName.substring(3);
                String newPropertyName;
                if (propertyName.length() > 1) {
                    newPropertyName = propertyName.substring(0, 1).toLowerCase() + propertyName.substring(1);
                } else {
                    newPropertyName = propertyName.substring(0, 1).toLowerCase();
                }
                stringWriter.append("\"").append(newPropertyName).append("\"")
                    .append(":");
                Class<?> returnType = method.getReturnType();
                if (returnType == String.class) {
                    stringPrint(stringWriter, (String) val);
                } else if (Number.class.isAssignableFrom(returnType)) {
                    numberPrint(stringWriter, (Number) val);
                } else if (Collection.class.isAssignableFrom(returnType)) {
                    Type type = method.getGenericReturnType();
                    collectionPrint(stringWriter, (Collection) val, type);
                    // 省略数组,map等各种类型的打印
                } else {
                    javaBeanPrint(stringWriter, val, val.getClass());
                }
                hasPrev = true;
            }

        }
        stringWriter.append("}");
    }

    private static void stringPrint(StringWriter stringWriter, String val) {
        stringWriter.append("\"").append(val).append("\"");
    }

    private static void numberPrint(StringWriter stringWriter, Number val) {
        if (val instanceof BigDecimal) {
            stringWriter.append(((BigDecimal) val).toPlainString());
        } else {
            stringWriter.append(val.toString());
        }
    }

    private static void collectionPrint(StringWriter stringWriter, Collection val, Type type) throws Exception {
        if(Objects.isNull(val) || val.size() == 0) {
            stringWriter.append("[]");
            return;
        }

        stringWriter.append("[");
        boolean havPrev = false;
        for (Object v : val) {
            if(Objects.isNull(v)) {
                continue;
            }
            if(havPrev) {
                stringWriter.append(",");
            }
            Class<?> vClass = v.getClass();
            if (vClass == String.class) {
                stringPrint(stringWriter, (String) v);
            } else if (Number.class.isAssignableFrom(vClass)) {
                numberPrint(stringWriter, (Number) v);
            } else if (Collection.class.isAssignableFrom(vClass)) {
                collectionPrint(stringWriter, (Collection) v, type);
                // 省略数组,map等各种类型的打印
            } else {
                javaBeanPrint(stringWriter, v, vClass);
            }
            havPrev = true;
        }
        stringWriter.append("]");
    }
}

以上是一个非常简单的实现,我们可以看到针对每种数据类型,它的序列化方式是不一样的,所以其实
我们可以使用策略模式加以改造,比如定义一个接口,加一个参数上下文,根据不同的数据类型实现
不同的序列化器。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值