Как преобразовать сущности, расширяющие универсальный класс, в другую сущность, расширяющую другой универсальный класс - PullRequest
2 голосов
/ 26 марта 2019

Я занимаюсь разработкой сервис-ориентированной платформы для извлечения, создания и обновления сущностей из БД.Дело в том, что каждая отдельная сущность Java расширяет AbstractEntity, поэтому, например, у меня есть

MyCar extends AbstractEntity implements Serializable

У этого AbstractEntity есть общие поля (такие как id или контрольные).Итак, я уже разработал GenericReadService, который, получив имя класса и parameterMap , может читать любую сущность и создает EntityActionResult<T>, включая List<T extends AbstractEntity>.

Моя проблема возникает при попытке преобразовать этот тип T во что-то вроде <K extends GenericDTO>, так как запрашивающий клиент не знает AbstractEntity (очевидно), а только GenericDTO.Делая это для безопасности и модульности.

Итак, теперь я застрял в преобразовании ListResponse<T> в ReturnList<K extends GenericDTO>, так как я не нахожу способ узнать, какой класс K должен применятьсядля каждого T.

Вот что я на самом деле написал:


    private GenericEntityActionResult transform (EntityActionResult result) {
        AsnGenericEntityActionResult r = new AsnGenericEntityActionResult();
        if (result.getCode() == EntityActionResult.Code.ENTITY || result.getCode() == EntityActionResult.Code.ENTITY_LIST ) {
            r.setCode(AsnGenericEntityActionResult.Code.OK);
            List <? extends GenericDTO> list = new ArrayList<>();
            if (result.getEntity() != null) {
                //transform this entity into DTO
                //<b>SOMETHING LIKE list.add(result.getEntity());</b>
            } else if (result.getList() != null && !result.getList().isEmpty()) {
                for (AbstractEntity a:result.getList()) {
                    //transform this entity into DTO
                    //<b>SOMETHING LIKE list.add(result.getEntity());</b>
                    //list.add(result.getEntity());
                }
            }
            r.setList(list);
        }
        return r;

Я, очевидно, застрял в ЧЕМ-ТО, КАК, но не могу найти подходящий способ сделать это.

Я думал о создании метода abstract <T extends GenericDTO> transformToDTO() на AbstractEntity, но не могу этого сделать, поскольку существует лотов (и я имею в виду сотни) сущностей, расширяющих AbstractEntity иэтот подход клиент-сервис является новой разработкой для некоторых организаций, а не для всей системы.

Какие-нибудь умные идеи?

1 Ответ

1 голос
/ 26 марта 2019

Вы можете попробовать использовать Java Introspection API или более надежную библиотеку поверх этого API, например apache commons beanutils , или даже более мощную библиотеку сопоставления бинов, например Dozer, или что-то более новое. см.

Следующий пример, демонстрирующий базовую технику, только необработанный самоанализ и отражение с двумя совместимыми бобами POJO.

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]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...