Java EntityMapper

Java EntityMapper

package org.rx.util;

import org.rx.common.Func2;
import org.rx.common.Action2;
import org.rx.common.Func1;
import org.rx.common.NQuery;
import org.rx.security.MD5Util;

import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * Created by wangxiaoming on 2016/3/11.
 */
public class EntityMapper {
    //region NestedTypes
    private static class MapEntity {
        public Func2<String, String, Boolean> MembersMatcher;
        public Object                         PostProcessor;
        public HashSet<String>                IgnoreNames;
    }

    private static class DefaultMatcher implements Func2<String, String, Boolean> {
        @Override
        public Boolean invoke(String arg1, String arg2) {
            return arg1.equals(arg2);
        }
    }
    //endregion

    //region Fields
    private static final String                     GET                = "get", SET = "set";
    private static final int                        getDefaultWhenNull = 1 << 0, putNewWhenNull = 1 << 1;
    private static final MapEntity                  Default;
    private static ConcurrentMap<String, MapEntity> Config;
    //endregion

    //region Methods
    static {
        Default = new MapEntity();
        Default.IgnoreNames = new HashSet<>();
        Default.IgnoreNames.add("getClass");
        Default.MembersMatcher = new DefaultMatcher();
        Config = new ConcurrentHashMap<>();
    }

    private static MapEntity getConfig(Class<?> tFrom, Class<?> tTo, int flags) {
        String key = getKey(tFrom, tTo);
        MapEntity map = Config.get(key);
        if (map == null) {
            if ((flags & getDefaultWhenNull) == getDefaultWhenNull) {
                return Default;
            }
            if ((flags & putNewWhenNull) == putNewWhenNull) {
                Config.putIfAbsent(key, map = new MapEntity());
                map.MembersMatcher = Default.MembersMatcher;
            }
        }
        return map;
    }

    private static String getKey(Class<?> tFrom, Class<?> tTo) {
        return MD5Util.md5Hex(tFrom.getName() + tTo.getName());
    }

    public static <T> T createInstance(Class<T> type) {
        try {
            return type.newInstance();
        } catch (ReflectiveOperationException ex) {
            throw new RuntimeException(ex);
        }
    }
    //endregion

    //region MapMethods
    public synchronized static <TF, TT> void setMembersMatcher(Class<TF> tFrom, Class<TT> tTo,
                                                               Func2<String, String, Boolean> membersMatcher,
                                                               Action2<TF, TT> postProcessor) {
        MapEntity map = getConfig(tFrom, tTo, putNewWhenNull);
        map.MembersMatcher = membersMatcher == null ? Default.MembersMatcher : membersMatcher;
        map.PostProcessor = postProcessor;
    }

    public synchronized static void setIgnoreMembers(Class<?> tFrom, Class<?> tTo, String... ignoreNames) {
        MapEntity map = getConfig(tFrom, tTo, putNewWhenNull);
        map.IgnoreNames = new HashSet<>(Arrays.asList(ignoreNames));
        map.IgnoreNames.add("getClass");
    }

    public static <TF, TT> TT[] map(Collection<TF> from, Class<TT> toType) {
        List<TT> toSet = new ArrayList<>();
        for (Object o : from) {
            toSet.add(map(o, toType));
        }
        TT[] x = (TT[]) Array.newInstance(toType, toSet.size());
        toSet.toArray(x);
        return x;
    }

    public static <TF, TT> TT map(TF from, Class<TT> toType) {
        return map(from, createInstance(toType));
    }

    public static <TF, TT> TT map(TF from, TT to) {
        return map(from, to, false);
    }

    public static <TF, TT> TT map(TF from, TT to, boolean skipNull) {
        Class<?> tFrom = from.getClass(), tTo = to.getClass();
        final MapEntity map = getConfig(tFrom, tTo, getDefaultWhenNull);

        NQuery<Method> fq = new NQuery<>(tFrom.getMethods()).where(new Func1<Method, Boolean>() {
            @Override
            public Boolean invoke(Method arg) {
                String fName = arg.getName();
                return !map.IgnoreNames.contains(fName) && fName.startsWith(GET);
            }
        });
        NQuery<Method> tq = new NQuery<>(tTo.getMethods()).where(new Func1<Method, Boolean>() {
            @Override
            public Boolean invoke(Method arg) {
                return arg.getName().startsWith(SET);
            }
        });

        for (Method fMethod : fq) {
            String fName = fMethod.getName();
            final String tName = SET + fName.substring(3);
            //App.logInfo("EntityMapper Step1 %s", fName);

            Method tMethod = tq.where(new Func1<Method, Boolean>() {
                @Override
                public Boolean invoke(Method arg) {
                    return map.MembersMatcher.invoke(tName, arg.getName());
                }
            }).firstOrDefault();
            Class<?>[] tArgs;
            if (tMethod == null || (tArgs = tMethod.getParameterTypes()).length != 1) {
                //App.logInfo("EntityMapper %s Miss %s.%s", tTo.getSimpleName(), tFrom.getSimpleName(), tName);
                continue;
            }
            //App.logInfo("EntityMapper Step2 %s to %s", fName, tName);

            try {
                Object value = fMethod.invoke(from);
                if (value == null && skipNull) {
                    continue;
                }
                value = App.changeType(value, tArgs[0]);
                tMethod.invoke(to, value);
            } catch (ReflectiveOperationException ex) {
                throw new RuntimeException(ex);
            }
        }

        if (map.PostProcessor != null) {
            Action2<TF, TT> postProcessor = (Action2<TF, TT>) map.PostProcessor;
            postProcessor.invoke(from, to);
        }
        return to;
    }
    //endregion

    public static void trim(Object entity) {
        Class<?> type = entity.getClass();
        NQuery<Method> fq = new NQuery<>(type.getMethods()).where(new Func1<Method, Boolean>() {
            @Override
            public Boolean invoke(Method arg) {
                return arg.getName().startsWith(GET) && arg.getReturnType().equals(String.class);
            }
        });

        for (Method method : fq) {
            try {
                String value = (String) method.invoke(entity);
                if (App.isNullOrEmpty(value)) {
                    continue;
                }
                method = type.getMethod(SET + method.getName().substring(3), String.class);
                method.invoke(entity, value.trim());
            } catch (ReflectiveOperationException ex) {
                throw new RuntimeException(ex);
            }
        }
    }

    public static Object getProperty(Object entity, String propName) {
        try {
            Method method = entity.getClass()
                    .getMethod(GET + propName.substring(0, 1).toUpperCase() + propName.substring(1));
            return method.invoke(entity);
        } catch (ReflectiveOperationException ex) {
            throw new RuntimeException(ex);
        }
    }
}

 

posted on 2017-08-10 17:22 RockyLOMO 阅读(...) 评论(...) 编辑 收藏

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值