java为实体动态添加字段

作者: 风一样的存在 | 来源:发表于2019-05-16 14:39 被阅读384次

        对于线上已经在用的接口,要动态的扩展返回数据的字段,并且不同的调用商需要的字段不一样,为了A客户增加了一个字段,不能把字段返回给B,防止B客户那边也要升级接口。对于开始加一两个字段我还可以接受:每次返回不同的实例,渐渐的我觉得力不从心了,代码重复太多了,就想到了能不能动态的添加字段呢?
    首先引入maven依赖:

            <dependency>
                <groupId>commons-beanutils</groupId>
                <artifactId>commons-beanutils</artifactId>
                <version>1.9.3</version>
            </dependency>
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-lang3</artifactId>
                <version>3.8</version>
            </dependency>
            <dependency>
                <groupId>cglib</groupId>
                <artifactId>cglib-nodep</artifactId>
                <version>3.2.4</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.16.22</version>
            </dependency>
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId>
                <version>2.9.6</version>
            </dependency>
    

    代码中使用:

    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.google.common.collect.Maps;
    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import net.sf.cglib.beans.BeanGenerator;
    import net.sf.cglib.beans.BeanMap;
    import org.apache.commons.beanutils.PropertyUtilsBean;
    
    import java.beans.PropertyDescriptor;
    import java.util.Map;
    
    /**
     * @author: jack
     * @Date: 2019/5/15 21:30
     * @Description: 动态添加类的属性
     */
    public class ReflectUtil {
        public static Object getTarget(Object dest, Map<String, Object> addProperties) {
            PropertyUtilsBean propertyUtilsBean =new PropertyUtilsBean();
            PropertyDescriptor[] descriptors = propertyUtilsBean.getPropertyDescriptors(dest);
            Map<String, Class> propertyMap = Maps.newHashMap();
            for(PropertyDescriptor d : descriptors) {
                if(!"class".equalsIgnoreCase(d.getName())) {
                    propertyMap.put(d.getName(), d.getPropertyType());
                }
            }
            // add extra properties
            addProperties.forEach((k, v) -> propertyMap.put(k, v.getClass()));
            // new dynamic bean
            DynamicBean dynamicBean =new DynamicBean(dest.getClass(), propertyMap);
            // add old value
            propertyMap.forEach((k, v) -> {
                try{
                    // filter extra properties
                    if(!addProperties.containsKey(k)) {
                        dynamicBean.setValue(k, propertyUtilsBean.getNestedProperty(dest, k));
                    }
                }catch (Exception e) {
                    e.printStackTrace();
                }
            });
            // add extra value
            addProperties.forEach((k, v) -> {
                try{
                    dynamicBean.setValue(k, v);
                }catch (Exception e) {
                    e.printStackTrace();
                }
            });
            Object target = dynamicBean.getTarget();
            return target;
        }
    
        public static class DynamicBean {
            /**
             * 目标对象
             */
            private Object target;
    
            /**
             * 属性集合
             */
            private BeanMap beanMap;
    
            public DynamicBean(Class superclass, Map<String, Class> propertyMap) {
                this.target = generateBean(superclass, propertyMap);
                this.beanMap = BeanMap.create(this.target);
            }
    
    
            /**
             * bean 添加属性和值
             *
             * @param property
             * @param value
             */
            public void setValue(String property, Object value) {
                beanMap.put(property, value);
            }
    
            /**
             * 获取属性值
             *
             * @param property
             * @return
             */
            public Object getValue(String property) {
                return beanMap.get(property);
            }
    
            /**
             * 获取对象
             *
             * @return
             */
            public Object getTarget() {
                return this.target;
            }
    
    
            /**
             * 根据属性生成对象
             *
             * @param superclass
             * @param propertyMap
             * @return
             */
            private Object generateBean(Class superclass, Map<String, Class> propertyMap) {
                BeanGenerator generator =new BeanGenerator();
                if(null != superclass) {
                    generator.setSuperclass(superclass);
                }
                BeanGenerator.addProperties(generator, propertyMap);
                return generator.create();
            }
        }
    
        @Data
        @Builder
        @AllArgsConstructor
        @NoArgsConstructor
        public static class Student {
            private String name;
            private String email;
        }
    
    
        public static void main(String[] args) throws Exception{
            Student student = Student.builder().name("jack").email("xy123zk@163.com").build();
            System.out.println(student.toString());
            Map<String,Object> properties = Maps.newHashMap();
            properties.put("address","浙江杭州");
            properties.put("age",26);
            ObjectMapper mapper = new ObjectMapper();
            String json = mapper.writeValueAsString(getTarget(student,properties));
            System.out.println(json);
        }
    }
    

    结果:

    image.png
    在spring集成的web项目可以直接使用spring提供的类,可以把依赖的net.sf.cglib.beans.BeanGeneratornet.sf.cglib.beans.BeanMap直接换成org.springframework.cglib.beans.BeanGeneratororg.springframework.cglib.beans.BeanMap

    参考:
    1.http://www.cnblogs.com/frinder6/p/7204574.html

    相关文章

      网友评论

        本文标题:java为实体动态添加字段

        本文链接:https://www.haomeiwen.com/subject/ygdbaqtx.html