考虑这个外部执行类
public class ExternalCommands {
private Logger log = LoggerFactory.getLogger(ExternalCommands.class);
private static final ObjectMapper objectMapper = new ObjectMapper();
public <T> CustomResponse<T> executeQuery(Clients client, Query query, Class<T> classType) throws Exception {
if (Objects.isNull(clients))
throw new Exception("external client is null in external commands");
log.debug("Query : {}", query);
Response queryResponse = clients.getElasticClient().executeQuery(query);
log.debug("query response : {}", queryResponse);
if (queryResponse.status() == 200) {
JavaType javaType = objectMapper.getTypeFactory().constructParametricType(CustomResponse.class, classType); // This is the coding sin m talking about
return objectMapper.readValue(queryResponse.body().asInputStream(), javaType);
}
}
}
所以基本上这个executeQuery
函数从弹性客户端获取query
的所有数据,并根据函数中发送的通用classType
对其进行反序列化。 />
这更像是显式执行deserialisation
而不是使用 Generics 。
见以下有关此执行如何与内联注释一起使用的代码:
public ArrayList<EmpData> getEmpData() throws Exception {
ArrayList<EmpData> merchantUrnMap = new ArrayList<>();
List<Filter> filters = new ArrayList<>();
filters.add("Added filter 1 here");
filters.add("Added filter 2 here");
filters.add("Added filter 3 here");
ExternalCommands commands = new ExternalCommands();
Query query = commands.getQuery(filters);
// get "clients"
// this is how it works now
CustomResponse<EmpData> response = commands.executeQuery(clients, query, EmpData.class);
// this is how i WANT IT TO WORK - without passing "EmpData.class"
// but in this case <T> in "CustomResponse<T>" would not deserialise to "EmpData"
// resulting in LinkedHashMap in deseralised object instead of class object
// CustomResponse<EmpData> response = commands.<EmpData>executeQuery(clients, query);
// some operations
return response
}
有关如何实现这一目标的任何建议?
答案 0 :(得分:2)
案例1:假设constructParametricType
要求classType
参数正常运行,并且您无法更改隐含但未在发布的代码中提供的方法/类的实现。
由于Java中的type erasure,您提出的方法签名/调用无法实现。
您在classType
来电中使用了constructParametricType(CustomResponse.class, classType)
,并且您试图以某种方式将classType
替换为T
。这是不可能的,因为编译代码时,T
将被完全删除。由于constructParametricType(CustomResponse.class, T.class)
在运行时不存在,因此无法执行T
之类的操作。
正确的解决方案是将类作为方法参数传递,这正是您现有方法所做的。
案例2:您确实希望接听电话commands.<EmpData>executeQuery(clients, query);
,并且您愿意更改任何内容以实现该目标。
由于我们无法将T
作为参数传递给constructParametricType
,因此必须将其称为constructParametricType(CustomResponse.class)
,但需要返回代表JavaType
的{{1}} 。唯一的方法是声明
CustomResponse<T>
请注意,<T> JavaType<T> constructParametricType(Class<?> cls)
现在也必须出于同样的原因进行参数化(我们无法在运行时获得JavaType
)。最后,我们必须声明
T
匹配声明的返回类型CustomResponse<T> readValue(InputStream stream, JavaType<T> javaType)
。
完成所有这些更改后,该行
executeQuery
应该编译。这是一个最小的例子:
CustomResponse<EmpData> response = commands.<EmpData>executeQuery(clients, query);
请注意,在系统的其余部分(特别是参数化class CustomResponse<T> {}
class Clients{}
class Query{}
class EmpData{}
class ObjectMapper {
JavaTypeFactory getTypeFactory() {
return new JavaTypeFactory();
}
<T> CustomResponse<T> readValue(InputStream s, JavaType<T> j) {
return new CustomResponse<>();
}
}
class JavaTypeFactory {
<T> JavaType<T> constructParametricType(Class<?> cls) {
return new JavaType<>(cls);
}
}
class JavaType<T> {
JavaType(Class<?> cls) {}
}
class ExternalCommands {
private static final ObjectMapper objectMapper = new ObjectMapper();
public <T> CustomResponse<T> executeQuery(Clients clients, Query query) throws Exception {
InputStream queryResponseStream = null;
JavaType<T> javaType = objectMapper.getTypeFactory().<T>constructParametricType(CustomResponse.class);
return objectMapper.readValue(queryResponseStream, javaType);
}
}
class SomeClass {
public void getEmpData() throws Exception {
ExternalCommands commands = new ExternalCommands();
Query query = null;
Clients clients = null;
CustomResponse<EmpData> response = commands.<EmpData>executeQuery(clients, query);
}
}
)中,某些所描述的更改可能并不容易/可能,并且我不推荐这种方法。我建议坚持你拥有的东西;这是IMO最干净的方法。