Ответ 1
Вы можете посмотреть dozer, который является
Java Bean в Java Bean mapper, который рекурсивно копирует данные с одного объекта на другой. Как правило, эти Java Beans будут иметь разные сложные типы.
В моей архитектуре приложения я обычно посылаю объект или список объектов с уровня доступа к данным на веб-уровень через сервисный уровень, в котором эти объекты преобразуются из DAO для объекта DTO и наоборот. Веб-уровень не имеет доступа к объектам DAO, а слой DAO не использует DTO.
Чтобы продемонстрировать, я обычно пишу код как:
@Transactional(readOnly = true)
public List<UserDTO> getAllUserAsUserDTO() {
List<UserDTO> userDTOs = new ArrayList<UserDTO>();
for(User user : getAllUser()) {
userDTOs.add(constructUserDTO(user));
}
return userDTOs;
}
private UserDTO constructUserDTO(User user) {
UserDTO userDTO = new UserDTO();
userDTO.setFullName(user.getFullName());
userDTO.setId(user.getId());
userDTO.setUsername(user.getUsername());
userDTO.setRole(user.getRole());
userDTO.setActive(user.isActive());
userDTO.setActiveText(user.isActive() ? "Active" : "Inactive");
return userDTO;
}
Здесь пользователь является объектом базы данных:
@javax.persistence.Entity
@Table(name = "USER")
public class User extends Entity {
@Transient
private static final long serialVersionUID = -112950002831333869L;
private String username;
private String fullName;
private boolean active;
private String role;
// other fields
public User() {
super();
}
@NaturalId
@Column(name = "USERNAME", nullable = false)
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@Column(name = "FULL_NAME")
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
@Column(name = "ACTIVE", nullable = false)
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
@Column(name = "ROLE")
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
}
И это UserDTO:
public class UserDTO extends BaseDTO {
private static final long serialVersionUID = -3719463614753533782L;
private String username;
private String fullName;
private String role;
private String activeText;
private Boolean active;
//other properties
public UserDTO() {
super();
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public String getActiveText() {
return activeText;
}
public void setActiveText(String activeText) {
this.activeText = activeText;
}
public Boolean getActive() {
return active;
}
public void setActive(Boolean active) {
this.active = active;
}
}
Итак, мне было интересно, является ли это единственным способом копирования свойств между двумя объектами. Наверное, я не уверен. Также я использую lambdaj, так есть метод в этом API, с помощью которого я могу скопировать все эти свойства, чтобы создать список других объектов
Этот раздел может звучать субъективно, но я действительно хочу узнать у вас экспертов, как можно преобразовать объект из одной формы в другую, где максимальные поля имеют одну и ту же строку.
Вы можете посмотреть dozer, который является
Java Bean в Java Bean mapper, который рекурсивно копирует данные с одного объекта на другой. Как правило, эти Java Beans будут иметь разные сложные типы.
Вы можете использовать Apache Commmons Beanutils. API
org.apache.commons.beanutils.PropertyUtilsBean.copyProperties(Object dest, Object orig)
.
Он копирует значения свойств из "origin" bean в "destination" bean для всех случаев, когда имена свойств одинаковы.
Теперь я собираюсь отключиться от темы. Использование DTO в основном рассматривается как анти-шаблон в EJB3. Если ваш DTO и ваши объекты домена очень похожи, нет необходимости дублировать коды. DTO по-прежнему имеет свои достоинства, особенно для экономии пропускной способности сети, когда задействован удаленный доступ. У меня нет деталей о вашей архитектуре приложения, но если слои, о которых вы говорили, являются логическими слоями и не пересекают сеть, я не вижу необходимости в DTO.
У меня было приложение, которое мне нужно было преобразовать из JPA в DTO, и я подумал об этом и, наконец, придумал org.springframework.beans.BeanUtils.copyProperties
для копирования простых свойств, а также расширения и использования org.springframework.binding.convert.service.DefaultConversionService
для преобразования сложных свойств.
Подробно моя служба была примерно такой:
@Service("seedingConverterService")
public class SeedingConverterService extends DefaultConversionService implements ISeedingConverterService {
@PostConstruct
public void init(){
Converter<Feature,FeatureDTO> featureConverter = new Converter<Feature, FeatureDTO>() {
@Override
public FeatureDTO convert(Feature f) {
FeatureDTO dto = new FeatureDTO();
//BeanUtils.copyProperties(f, dto,"configurationModel");
BeanUtils.copyProperties(f, dto);
dto.setConfigurationModelId(f.getConfigurationModel()==null?null:f.getConfigurationModel().getId());
return dto;
}
};
Converter<ConfigurationModel,ConfigurationModelDTO> configurationModelConverter = new Converter<ConfigurationModel,ConfigurationModelDTO>() {
@Override
public ConfigurationModelDTO convert(ConfigurationModel c) {
ConfigurationModelDTO dto = new ConfigurationModelDTO();
//BeanUtils.copyProperties(c, dto, "features");
BeanUtils.copyProperties(c, dto);
dto.setAlgorithmId(c.getAlgorithm()==null?null:c.getAlgorithm().getId());
List<FeatureDTO> l = c.getFeatures().stream().map(f->featureConverter.convert(f)).collect(Collectors.toList());
dto.setFeatures(l);
return dto;
}
};
addConverter(featureConverter);
addConverter(configurationModelConverter);
}
}
Вы можете использовать отражение, чтобы найти все методы get
в объектах DAO и вызвать эквивалентный метод set
в DTO. Это будет работать, только если все такие методы существуют. Для этого должно быть легко найти пример кода.
Не будет lambdaj функция проекта делает то, что вы ищете?
Он будет выглядеть примерно так:
List<UserDTO> userNDtos = project(users, UserDTO.class, on(User.class).getUserName(), on(User.class).getFullName(), .....);
(Определите конструктор для UserDTO соответственно...)
Также см. здесь для примеров...