我正在尝试从我的类Configuration中加载方法Customer.cypher和Customer.cypherCBC方法。客户类是从不同环境渲染的,因此很少有环境使用cypherCBC()和cypher()方法,而很少有环境只有cypher()方法。
现在我想检查cypherCBC是否在Customer类中,然后加载cypher()方法。我的功能到目前为止;
try {
Class<?> customerClass = Class.forName("com.myapp.impl.service.Customer");
Object obj = customerClass.newInstance();
//here getting "NoSuchMethodException" exception
Method methodCBC = customerClass.getDeclaredMethod("cypherCBC", String.class); //line - 7
if(methodCBC.getName().equals("cypherCBC")){
methodCBC.invoke(obj, new String(dbshPass));
System.out.println("CYPHER_CBC: "
+ methodCBC.invoke(obj, new String(dbshPass)));
}else{
Method method = customerClass.getDeclaredMethod("cypher", String.class);
method.invoke(obj, new String(dbshPass));
System.out.println("CYPHER: " + method.invoke(obj, new String(dbshPass)));
}
}catch (Exception e){
e.printStackTrace();
}
在第7行获取错误。
NoSuchMethodException: com.myapp.impl.service.Customer.cypherCBC(java.lang.String中)
这意味着对于特定的环境类,客户没有cypherCBC()方法,但理想情况下它应该是其他部分并执行cypher()方法。
Class<?> client = null;
Object obj = null;
try{
client = Class.forName("com.myapp.impl.service.Client");
obj = client.newInstance();
}catch (InstantiationException ex) {
System.err.println("Not able to create Instance of Class");
} catch (IllegalAccessException ex) {
System.err.println("Not able to access Class");
} catch (ClassNotFoundException ex) {
System.err.println("Not able to find Class");
}
try {
Method methodCBC = client.getDeclaredMethod("cypherCBC", String.class);
System.out.println("CYPHER_CBC: " + methodCBC.invoke(obj, new String(dbshPass)));
}catch (NoSuchMethodException ex) {
System.err.println("Not able to find Method on class");
ex.printStackTrace();
} catch (Exception e){
e.printStackTrace();
}
答案 0 :(得分:2)
这正是预期的结果:getDeclaredMethod()在没有符合您的规范的方法时抛出该异常。你想知道如果缺少必要的方法会引发异常吗?提示:下次更好地阅读javadoc。不要认为某些事情能做某事,而是要验证你的假设!
此外:再次阅读您的代码。它在做什么?你问“给我一个名为'foo'的方法”。然后,您的下一步是要求该方法“是您的名字'foo'”。所以即使没有阅读javadoc,也应该清楚你的逻辑存在缺陷。
作为解决方案,您可以自己实现非投掷查找,例如
private Method lookupCypher(Class<?> client, String methodName) {
for (Method declaredMethod : client.getDeclardMethods()) {
if (declaredMethod.getName().equals(methodName)) {
Class<?>[] parameterTypes = declaredMethod.getParameterTypes();
if (parameterTypes.length == 1 && parameterTypes[0].equals(String.class)) {
// so declaredMethod has the given name, and takes one string as argument!
return declaredMethod;
}
}
// our search didn't reveal any matching method!
return null;
}
使用该帮助器方法,您可以将代码重写为:
Method toInvoke = lookupCypher(client, "cypherCBC");
if (toInvoke == null) {
toInvoke = lookupCypher(client, "cypher");
}
toInvoke(obj, new String ...
或者,考虑到猎人的想法;一个更“喜欢”的版本:
interface CustomerCypherWrapper {
void cypher(String phrase);
}
class NewCustomerWrapper() implements CustomerCypherWrapper {
@Override
void cypher(String phrase) {
new Customer.cypherCBC(phrase);
}
}
class oldCustomerWrapper() implements CustomerCypherWrapper {
@Override
void cypher(String phrase) {
new Customer.cypher(phrase);
}
}
您的客户端代码归结为:
CustomerCypherWrapper wrapper =
(lookupCypher(..., "cypherCBC") == null)
? new NewCustomerWrapper()
: new OldCustomerWrapper();
wrapper.cypher();
[我希望你注意到我的版本A)更容易阅读和B)不再包含任何重复的代码。 ]
是的,查找方法的替代实现可能就像
private Method lookupCyper(Client<?>, String methodName) {
try {
return client.getDeclaredMethod(methodName, String.class);
} catch ....
and return null;
}
... return your public cypherCBC method
但这在Java中是一种“不常见的做法”。在Java中,我们要求许可;而不是原谅。与其他languages
不同答案 1 :(得分:1)
如果您使用具有这两种方法的Customer类编译应用程序,您可以使用反射一次来检查cypherCBC方法是否在运行时可用,那么您可以保持该状态,您可以在不使用反射的情况下调用该方法< / p>
if(newVersion)
{
customer.cypherCBC(arg);
}
else
{
customer.cypher(arg);
}
但是要编写更好的应用程序,您应该使用两个版本基准。 即使这是一个小代码片段,您应该设置另一个模块来隐藏此Customer类及其交互,该模块应该有两个版本。但是您的主模块只有单个版本。现在,当您交付应用程序时,应根据目标环境的兼容性将产品打包为正确的版本基准。
答案 2 :(得分:0)
虽然反射有效(如其他答案中所述)。如果您可以控制Customer
类,则可以尝试非反射方法。
interface CBCCypherable {
public String cypherCBC(String pass);
}
您现在可以拥有两个版本的Customer
类,一个实现CBCCypherable
,另一个不实现Customer c = new Customer();
if (c instanceof CBCCypherable) {
((CBCCypherable)c).cypherCBC(pass);
} else {
c.cypher(pass);
}
。当你打电话时,它看起来像这样:
.then(response => {
response.text().then(text => {
// handle response content
})
})
使用此解决方案可以获得更简单的代码,作为奖励,编译器将检查您是否使用了正确的方法名称和参数类型。与反射不同,那就是你的全部工作,你必须运行代码来查明是否有错误。
Ps:我不知道这只是示例代码,或者你真的在这里加密/散列密码,但通常认为推出自己的安全代码是个坏主意。