我正在开发一个面向服务的平台,用于从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 }},而这种客户服务方法是某些实体(而不是整个系统)的新开发。
有什么聪明的主意吗?
答案 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]