我有以下界面:
public interface Mapper {
public SomeType methodOne(HashMap<String, Object>);
public OtherType methodTwo(HashMap<String, Object>);
...
}
那么可以将methodOne
或methodTwo
作为另一个类中的参数调用吗?
public class Other {
public void doSomething(HashMap<String, Object> params, ????) {
Mapper mapper = new ConcreteMapper();
mapper.methodOne(params);
}
}
我尝试了java反射但是在编译时我无法获得HashMap<String, Object>
的类型。我想知道有没有办法解决这个问题呢?
动机来自我在工作场所遇到的一个真正的问题。例如,每个REST
方法调用唯一不同的是getAddressPhone
和AddressPhoneType
。像开放SQL会话,实例化Mapper
这些嘈杂的步骤基本相同。
public Response getAddressPhone(@PathParam("acc_nbr") String accNbr, @HeaderParam("AuthToken") String authToken) {
SqlSession session = ConnectionFactory.getSqlSessionFactory().openSession();
Logger log = LoggerFactory.getLoggerFactory();
AddressPhoneType addressPhone = null;
try {
MyAccountMapper mapper = session.getMapper(MyAccountMapper.class);
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("acc_nbr", accNbr);
addressPhone = mapper.getAddressPhone(map);
if (addressPhone == null) {
return Response.ok(null).status(Status.NOT_FOUND).build();
}
} catch (Exception e) {
log.debug("getAddressPhone(map):" + e.getMessage());
return Response.ok().status(Status.BAD_REQUEST).build();
} finally {
session.close();
}
return Response.ok(gson.toJson(addressPhone)).header("AuthToken", authToken).status(Status.OK).build();
}
修改
我正在使用MyBatis映射器来执行MySql查询,因此我有以下名为MyAccountMapper
的接口。由于这些方法中的每一个都在SQL查询中使用id进行映射,因此没有它们的定义:
public interface MyAccountMapper {
AddressPhoneType getAddressPhone(HashMap<String, Object> map);
AdminUserInfoType getAdminUserInfo(HashMap<String, Object> map);
DueDateInfoType getDueDateInfo(HashMap<String, Object> map);
....
}
现在在我的所有Web服务调用中(我正在使用JAX-RS),我需要调用这些方法来对我的数据库执行某些操作,正如您在上面的示例中所看到的,大多数内容都像设置映射器一样,创建记录器是一样的。唯一不同的是方法调用和返回类型。
@GET
@Path("/admin/user/info/{acc_nbr}")
@Produces("application/json")
public Response getAdminUserInfo(@PathParam("acc_nbr") String accNbr) {
SqlSession session = ConnectionFactory.getSqlSessionFactory().openSession();
AdminUserInfoType adminUserInfoType = null;
Logger log = LoggerFactory.getLoggerFactory();
try {
MyAccountMapper mapper = session.getMapper(MyAccountMapper.class);
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("acc_nbr", accNbr);
adminUserInfoType = mapper.getAdminUserInfo(map);
if (adminUserInfoType == null) {
return Response.ok(gson.toJson(null)).status(Status.NOT_FOUND).build();
}
} catch (Exception e) {
log.debug("getAdminUserInfo(map):" + e.getMessage());
return Response.ok("getAdminUserInfo(map):"+ MyBatisErrorMessage.SELECT_ERROR).status(Status.BAD_REQUEST).build();
} finally {
session.close();
}
return Response.ok(gson.toJson(adminUserInfoType)).status(Status.OK).build();
}
@GET
@Path(value = "/address/phone/{acc_nbr}")
@Produces(MediaType.APPLICATION_JSON)
public Response getAddressPhone(@PathParam("acc_nbr") String accNbr,
@HeaderParam("AuthToken") String authToken) {
SqlSession session = ConnectionFactory.getSqlSessionFactory().openSession();
Logger log = LoggerFactory.getLoggerFactory();
AddressPhoneType addressPhone = null;
try {
MyAccountMapper mapper = session.getMapper(MyAccountMapper.class);
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("acc_nbr", accNbr);
addressPhone = mapper.getAddressPhone(map);
if (addressPhone == null) {
return Response.ok(null).status(Status.NOT_FOUND).build();
}
} catch (Exception e) {
log.debug("getAddressPhone(map):" + e.getMessage());
return Response.ok("getAddressPhone(map):"+ MyBatisErrorMessage.SELECT_ERROR).status(Status.BAD_REQUEST).build();
} finally {
session.close();
}
return Response.ok(gson.toJson(addressPhone)).header("AuthToken", authToken).status(Status.OK).build();
}
答案 0 :(得分:2)
public interface Method {
public Object invoke(Map<> params);
}
public void invokeTheMethod(Map<> params, Method method) {
// ... do common work here ...
Object result = method.invoke(params);
// ... handle result here ...
}
// run common invoker with Mapper.methodOne
invokeTheMethod(params, new Method() {
public Object invoke(Map<> params) {
return mapper.methodOne(params);
});
答案 1 :(得分:1)
因为函数不是Java中的对象(至少现在还没有),所以你不能以一种简单的方式做你想做的事。
如果您不介意丢弃返回值(就像您使用Other.doSomething
一样),那么接口和几个实现可以完成这项工作。实现可以是单例。
interface MethodCaller {
void callMethod(HashMap<String, Object> args, Mapper mapper);
MethodCaller methodOneCaller = new MethodCaller() {
@Override
public void callMethod(HashMap<String, Object> args, Mapper mapper) {
mapper.methodOne(args);
}
}
MethodCaller methodTwoCaller = new MethodCaller() {
@Override
public void callMethod(HashMap<String, Object> args, Mapper mapper) {
mapper.methodTwo(args);
}
}
}
然后你可以将其中一个来电者传递给任何想要使用它们的人:
public class Other {
public void doSomething(HashMap<String, Object> params, MethodCaller caller) {
Mapper mapper = new ConcreteMapper();
caller.callMethod(params, mapper);
}
}
Other other = . . .;
HashMap<String, Object> stuff = . . .;
other.doSomething(stuff, MethodCaller.methodOneCaller);
other.doSomething(stuff, MethodCaller.methodTwoCaller);
答案 2 :(得分:1)
嗯,这就是在给定具体实例的情况下,可以使用反射来调用任一方法:
Mapper concreteMapper = new ConcreteMapper();
Method method1 = concreteMapper.getClass().getMethod("methodOne", HashMap.class);
Method method2 = concreteMapper.getClass().getMethod("methodTwo", HashMap.class);
method1.invoke(concreteMapper, new HashMap<String, Object>());
method2.invoke(concreteMapper, new HashMap<String, Object>());
但是如果你只是想避免锅炉板代码考虑使用类似命令模式的东西。或者,如果你使用spring,这对于它的AOP来说是一个很好的用例。
答案 3 :(得分:1)
我认为需要一个mapper工厂,并且还需要修改mapper接口。
public interface Mapper {
public SomeType method(HashMap<String, Object> map);
}
public class MapperFactory {
public static Mapper createMapper(some parameters here) {
// create a mapper according to the parameters.
}
}
// usage within another class
public class Other {
public void doSomething(HashMap<String, Object> params, ????) {
Mapper mapper = new MapperFactory.createMapper(......);
mapper.method(params);
}
}