Рамки для преобразования Java-объектов

Я работаю над проектом, который преобразует объекты базы данных в объекты DTO. Для этого для каждого преобразования используется специальный класс преобразователя.


Я предоставляю упрощенный пример того, что мы делаем. Я намеренно пропустил сеттеры/геттеры и некоторые другие вещи для ясности кода.

Итак, вот постоянные объекты:

class Car {
    String number;
    Driver driver;
}

class Driver {
    String name;
    License license;
}

class License {
    String serial;
    Date expired;
} 

И предполагая, что нам нужен следующий объект DTO:

class DriverDTO {
    String name;
    String carNumber;
    String licenseSerial;
}

Мы создаем следующий класс преобразователя:

class DriverDTOConverter {
    DriverDTO convert(Car car) {
        DriverDTO driverDto = new DriverDTO();
        driverDto.carNumber = car.number;
        driverDto.name = car.driver.name;
        driverDto.licenseSerial = car.driver.license.serial;
        return driverDto;
    }
}

И немного более сложный пример:

class CarDTO {
    String number;
    String driverName;
    LicenseDTO driverLicense;
}

class LicenseDTO {
    String serial;
}

class CarDTOConverter {
    CarDTO convert(Car car) {
        CarDTO carDto = new CarDTO();
        carDto.number = car.number;
        carDto.driverName = car.driver.name;
        LicenseDtoConverter c = new LicenseDtoConverter();
        carDto.driverLicense = c.convert(car.driver.license);
        return carDto;
    }
}

class LicenseDtoConverter {
    LicenseDTO convert(License license) {
        LicenseDTO licenseDto = new LicenseDTO();
        licenseDto.serial = license.serial;
        return licenseDto;
    }
}

Требуется много времени, поэтому я задаюсь вопросом, есть ли какая-либо структура, которая может взять на себя ответственность за эту работу. И мне нужно будет только настроить его с помощью файлов свойств или аннотаций.

Smth, подобный этому

Если файл свойства:

DriverDto <--> Car {
carNumber = number;
name = driver.name;            
licenseSerial = driver.license.serial;
}

CarDTO <--> Car {
number = number;
driverName = driver.name;
driverLicense = driver.license;
}

LicenseDTO <--> License {
license = license;
}

Или пример возможного аннотированного объекта

@Converted(Car.class)
class DriverDTO {
    @Associated("driver.name")
    String name;
    @Associated("number")
    String carNumber;
    @Associated("driver.license.serial")
    String licenseSerial;
}

Важным требованием является то, что он не должен использовать никакого отражения. Все аннотации или файлы свойств должны быть скомпилированы на этапе компиляции или прекомпиляции, и должен генерироваться байт-код или исходный код.

Я буду очень рад, если кто-нибудь может указать мне на такую ​​структуру. Я также с удовольствием буду участвовать в его создании, если он все еще находится на стадии развития.

Ответ 1

Вы должны проверить Dozer - Java bean to bean mapper. Прост в использовании, легко расширяется.

Ответ 2

Вы можете проверить ModelMapper.

Он отличается от Dozer и других тем, что он минимизирует объем конфигурации, необходимый для интеллектуального сопоставления объектных моделей. В случае необходимости конфигурации ModelMapper предлагает безопасный API для рефакторинга, который использует фактический код для сопоставления свойств и значений, а не с использованием ссылок на строки или XML.

Зайдите на сайт ModelMapper для получения дополнительной информации:

http://modelmapper.org

Ответ 3

Одной из альтернатив dozer, которую вы можете найти, является jDTO Binder, она очень проста в использовании и обеспечивает интеграцию с наиболее популярными бэкэнд-контейнерами.

jDTO Binder

Ответ 4

Вам может быть интересно MapStruct, который является генератором кода времени компиляции для именно этого варианта использования (отказ от ответственности: я работаю по этому проекту).

Поскольку MapStruct - это инструмент времени построения, он не использует отражение и не требует определенных зависимостей времени исполнения. Вам нужно объявить интерфейс следующим образом:

@Mapper
public interface CarMapper {

    CarMapper INSTANCE = Mappers.getMapper ( CarMapper.class );

    @Mapping(source="number", target="carNumber")
    @Mapping(source="driver.name", target="name")
    @Mapping(source="driver.license.serial", target="licenseSerial")
    CarDto carToCarDto(Car car);

    DriverDto driverToDriverDto(Driver driver);
}

Во время сборки (например, через Maven или в вашей среде IDE) MapStruct генерирует реализацию этого интерфейса, которая в основном похожа на ваш оригинальный ручной код.

Если вам интересно, вы можете узнать больше в справочном руководстве.