如何将扩展泛型类的实体转换为扩展另一泛型类的实体

时间:2019-03-26 17:51:21

标签: java oop

我正在开发一个面向服务的平台,用于从DB检索,创建和更新实体。 这里的要点是,每个单个Java实体都扩展了AbstractEntity,例如,我拥有

MyCar extends AbstractEntity implements Serializable

AbstractEntity具有公共字段(例如id或audit字段)。 因此,我已经开发了一个GenericReadService,它接收到 classname parameterMap ,可以读取任何实体并创建一个包含{{ 1}}。

我的问题出在尝试将EntityActionResult<T>类型转换成类似List<T extends AbstractEntity>的问题时,因为询问的客户不知道T(很明显),但是只知道<K extends GenericDTO>。这样做是为了安全和模块化。

因此,现在,我一直坚持将AbstractEntity转换为GenericDTO,因为我没有找到知道哪个ListResponse<T>类适用于每个{{ 1}}。

这是我实际上写的:

ReturnList<K extends GenericDTO>

我显然很喜欢类似的东西,但找不到合适的方法。

我曾考虑过在K上创建T方法,但是由于存在扩展了{{1 }},而这种客户服务方法是某些实体(而不是整个系统)的新开发。

有什么聪明的主意吗?

1 个答案:

答案 0 :(得分:1)

您可以尝试在此API之上使用Java Introspection API或更强大的库,例如apache commons beanutils,或者使用更强大的bean映射库,例如Dozer或更新的see

下面的示例演示了基本技术,仅对两个兼容的POJO bean进行了原始的自省和反思。

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;


class Tranformation {


    public static void main(String[] args) {

        MyCar car = new MyCar();
        car.setId("id01");
        car.setName("Komodo");
        car.setMadeIn("Jakarta");

        CarDTO dto = toDto(CarDTO.class, car);

        System.out.println(dto);

    }

    public <E extends AbstractEntity, D extends GenericDTO> D toDto(Class<D> dtoClass, E entity) {
        if (null == entity) {
            throw new NullPointerException("Entity can not be null");
        }
        try {
            final D ret = dtoClass.newInstance();

            BeanInfo dtoBeanInfo = Introspector.getBeanInfo(dtoClass);

            final Map<String, PropertyDescriptor> mapping = Arrays.stream(dtoBeanInfo.getPropertyDescriptors())
                    .collect(Collectors.toMap(PropertyDescriptor::getName, Function.identity()));

            final BeanInfo entityBeanInfo = Introspector.getBeanInfo(entity.getClass());

            Arrays.stream(entityBeanInfo.getPropertyDescriptors()).forEach(src -> {
                if (!"class".equals(src.getName())) {
                    PropertyDescriptor dst = mapping.get(src.getName());
                    if (null != dst) {
                        try {
                            dst.getWriteMethod().invoke(ret, src.getReadMethod().invoke(entity, null));
                        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                            throw new IllegalStateException(e);
                        }
                    }
                }
            });

            return ret;
        } catch (InstantiationException | IntrospectionException | IllegalAccessException e) {
            throw new IllegalStateException(e);
        }
    }

    public static class GenericDTO {
        private String id;
        private String name;

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

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

    }

    public static class CarDTO extends GenericDTO {
        private String madeIn;

        public String getMadeIn() {
            return madeIn;
        }

        public void setMadeIn(String madeIn) {
            this.madeIn = madeIn;
        }

        @Override
        public String toString() {
            return String.format("CarDTO [id=%s, name=%s, madeIn=%s]", getId(), getName(), madeIn);
        }

    }

    public static class AbstractEntity implements Serializable {
        private static final long serialVersionUID = 70377433289079231L;
        private String id;
        private String name;

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

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

    public static class MyCar extends AbstractEntity {
        private static final long serialVersionUID = 8702011501211036271L;
        private String madeIn;

        public String getMadeIn() {
            return madeIn;
        }

        public void setMadeIn(String madeIn) {
            this.madeIn = madeIn;
        }

    }

}

输出:

CarDTO [id=id01, name=Komodo, madeIn=Jakarta]