I am trying to load methods Customer.cypher and Customer.cypherCBC method from my class Configuration. Customer class is rendering from different environments so few environmets are having cypherCBC() and cypher() method and few are having only cypher() method.
Now i want to check if cypherCBC if not there in Customer class then load cypher() method. My function is so far;
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();
}
Getting an error at line 7.
NoSuchMethodException:
com.myapp.impl.service.Customer.cypherCBC(java.lang.String)
that means for particular environment class Customer doesn't having cypherCBC() method, but ideally it should come in else part and execute cypher() method.
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();
}
That is exactly what is to be expected: getDeclaredMethod() throws that exception when no method exists that meets your specification. And you are wondering that it throws an exception if the required method is missing? Hint: better read the javadoc next time. Don't assume that something does something, but verify your assumptions!
Besides: read your code again. What is it doing? You are asking "give me the method named 'foo'". And then, your next step is to ask that method "is your name 'foo'". So even without reading javadoc, it should become clear that your logic is flawed.
As solution, you can implement a non-throwing lookup yourself, like
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;
}
Using that helper method, you can rewrite your code to:
Method toInvoke = lookupCypher(client, "cypherCBC");
if (toInvoke == null) {
toInvoke = lookupCypher(client, "cypher");
}
toInvoke(obj, new String ...
Or, with the idea from hunter in mind; a much more "OO like" version:
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);
}
}
And your client code boils down to:
CustomerCypherWrapper wrapper =
(lookupCypher(..., "cypherCBC") == null)
? new NewCustomerWrapper()
: new OldCustomerWrapper();
wrapper.cypher();
[ I hope you notice that my version A) is easier to read and B) doesn't contain any duplicated code any more. ]
And yes, an alternative implementation of the lookup method could just go like
private Method lookupCyper(Client<?>, String methodName) {
try {
return client.getDeclaredMethod(methodName, String.class);
} catch ....
and return null;
}
... return your public cypherCBC method
But that is an "uncommon practice" in Java. In Java, we ask for permission; instead of forgiveness. Unlike other languages
if you compile the application with a Customer class which has both method,you can use reflection once to check whether the cypherCBC method available or not at runtime, then you can keep that status, you can call the method without using reflection
if(newVersion)
{
customer.cypherCBC(arg);
}
else
{
customer.cypher(arg);
}
But to write a better application,you should use two version baselines.
even though this is a small code fragment you should setup a another module to hide this Customer class and its interactions,that module should have two versions. but your main module has only single version.Now when you you deliver the application , product should be packaged with right version baseline based on compatibility for the target environment.
Although reflection works (as explained in the other answers). if you have control over the Customer class, you can try a non-reflection approach.
interface CBCCypherable {
public String cypherCBC(String pass);
}
You can now have two versions of Customer class, one that implements CBCCypherable and one that doesn't. And when you call it, it looks like this:
Customer c = new Customer();
if (c instanceof CBCCypherable) {
((CBCCypherable)c).cypherCBC(pass);
} else {
c.cypher(pass);
}
What you get with this solution is much simpler code, and as a bonus the compiler will check that you use the correct method name and parameter types. Unlike with reflection, where that's all your job, and you have to run the code to find out if something's wrong.
P.s.: I don't know if this is just sample code or you are really encrypting/hashing passwords here, but it's generally considered a bad idea to roll your own security code.
Related
I am having troubles while trying to refactor exception handling logic in an helper class.
My code uses a repository which accesses a database and might throw the custom exception RepositoryException. If such exception is thrown by the repository, I want my code to catch it and set an error label in the graphical user interface (view):
... // more code
try {
existingCourse = repository.findByTitle(course.getTitle()); // <- throws RepositoryException
} catch (RepositoryException e) {
view.showError(e.getMessage(), course);
return;
}
... // some more code
The point is that this code is repeated several times and I would prefer to have it refactored in an helper class.
This is what I came up to after some experiments:
A custom FunctionalInterface called ThrowingSupplier, which represent the code that throws the exception.
A TransactionManager helper class, with a catcher methods that accepts a ThrowingSupplier
This is the related code (BaseEntity is just a base class for entities in my domain, as you might guess):
// ThrowingSupplier.java
#FunctionalInterface
public interface ThrowingSupplier<T extends BaseEntity> {
T get() throws RepositoryException;
}
/* ------------------------------------------------------ */
// ExceptionManager.java
public final class ExceptionManager<T extends BaseEntity> {
private T result;
private String exceptionMessage;
ExceptionManager() {
}
public boolean catcher(ThrowingSupplier<T> supplier) {
try {
clearResult();
clearExceptionMessage();
result = supplier.get();
return true;
} catch (RepositoryException e) {
exceptionMessage = e.getMessage();
}
return false;
}
// public getters and 'clearers' for attributes
...
}
And this is how I am using this now:
...
em = new ExceptionManager();
... // more code
if (!em.catcher(() -> repository.findByTitle(course.getTitle()))) {
view.showError(em.getExceptionMessage(), course);
return;
}
existingCourse = em.getResult();
... // some more code
Now it seems to me that this does not give any advantages with respect to using directly the try catch in every repository invocation. This is mainly because I need both the return value of the repository method and a way to tell the caller if the repository call has been successful. As a variation I tried to add the showError call inside catcher, but then I must pass view and entity in every invocation of catcher, which I do not like very much as it makes the code less readable.
Is there another way to accomplish this in an elegant manner or it is better to leave the try catch in every call to the repository? Also, what is the standard way to deal with this problem?
I'm using Reflection to Mock a private method (I don't want to discuss if that makes sense or not).
Anyone know why? I'll let my testClass source code here it may help. I've tryed much of the Internet helps and ways to solve this but none have worked for me.
public class testProtexManagerProcessRequiredFile {
#Mock
ProtexManager PxManager;
#Before
public void inicializa() {
MockitoAnnotations.initMocks(this);
}
#Test
public void processRequiredFileTest() throws ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, InstantiationException {
Method method;
try {
method = ProtexManager.class.getDeclaredMethod("processRequiredFile", File.class);
method.setAccessible(true);
File FileExample = new File();
String NameExample = "Nome";
File outputs = new File();
outputs = (File) Mockito.when(method.invoke(PxManager, FileExample,NameExample)).thenReturn(FileExample);
assertNotNull(outputs);
assertEquals(outputs, method.invoke(PxManager, FileExample,NameExample));
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Teste Concluido.");
}
}
That's the method code:
private File processRequiredFile(File file, String name) {
if (!file.exists()) {
this.message = name + " file not found at location: " + file;
this.msgResponse.addMsgList(MsgCode.FAILURE, MsgLevel.ERROR, this.message, StringUtils.EMPTY);
}
return file;
}
And thank you all for helping me in my doubts.
To answer your question,
Because you caught the NoSuchMethodException. To get a test failure you have to somehow get some exception or error during the test execution
To follow up on the comments, here's how one can test this method:
// let's assume there are getter for this.message / this.msgResponse
// and this method is in the class foo.bar.Foobar
protected File processRequiredFile(File file, String name) {
if (!file.exists()) {
this.message = name + " file not found at location: " + file;
this.msgResponse.addMsgList(MsgCode.FAILURE, MsgLevel.ERROR, this.message, StringUtils.EMPTY);
}
return file;
}
In a test class foo.bar.FoobarTest:
#Mock
private File file;
private Foobar foobar = new Foobar();
#Test
public void testWithNonExistingFile() {
Mockito.when(this.file.exists()).thenReturn(false); // this is to illustrate, you could also use some non existent file: new File("/does-not-exists.foo")
File result = this.foobar.processRequiredFile(this.file, "some name");
assertThat(result).isEqualTo(this.file);
assertThat(foobar.getMsgResponse()).isNotEmpty(); // TODO: better assertion
assertThat(foobar.getMessage()).isEqualTo( "some name file not found at location: " + this.file);
}
#Test
public void testWithExistingFile() {
Mockito.when(this.file.exists()).thenReturn(true);
File result = this.foobar.processRequiredFile(this.file, "some name");
assertThat(result).isEqualTo(this.file);
assertThat(foobar.getMsgResponse()).isEmpty();
assertThat(foobar.getMessage()).isNull();
}
The class under test (i.e. Foobar) is really tested, this uses a real instance of it and call its method. A mock is used to replace something we don't have (here it's a file to illustrate but it's usually something more complicated)
What is your actual question? Why the testcase succeeds? That's already answered in the comments. You catch the exception and essentially ignore it. If you want to see the stacktrace on STDERR and let the testcase fail, you have to initiate the failing procedure yourself, e.g by calling
throw (AssertionFailedError) new AssertionFailedError("method not found").initCause(e);
This construct looks strange but JUnit 3 (I assume you're using that given your code) doesn't come with an AssertionFailedError with a constructor allowing to pass a cause. This way you see the stacktrace in your IDE as well and will be visible in JUnit-reports created during build processes.
Or is your question why the particular method is not found? One reason can be that someClass.getDeclaredMethod only returns a result if the method is declared in that particular class. If that class has a super class inheriting this method, you have to use the superclass when calling getDeclaredMethod to get the method.
If you don't know what class actually contains a method you have to iterate over all superclasses until reaching the "end":
Class<?> clazz = ProtexManager.class;
while (clazz != null) {
try {
return clazz.getDeclaredMethod("processRequiredFile", File.class);
catch(NoSuchMethodException e) {
clazz = clazz.getSuperClass();
}
}
That code block swallows the NoSuchMethodException but I don't want to do things more complicated than necessary to illustrate the idea.
Another reason why the method is not found might be that the class in question has a method processRequiredFile(java.io.File) and not processRequiredFile(com.blackducksoftware.sdk.codecenter.deeplicense.data.File). Also you later call the method by method.invoke using three parameters (PxManager, File, String) so either your call of getDeclaredMethod is missing parameter classes or your call of invoke will later fail due to the differences between declaration of the method and passed parameters.
I am trying to learn Method Reflect so I can apply in my Java application.
I created two POJO classes.
Wishes.java
public class Wishes {
private String greeting;
public String getGreeting() {
this.greeting="Good Afternoon!";
return greeting;
}
public void setGreeting(String greeting) {
this.greeting = greeting;
}
}
Day.java
public class Day {
private Wishes wishes;
public Wishes getWishes() {
return wishes;
}
public void setWishes(Wishes wishes) {
this.wishes = wishes;
}
}
This is what I do in my main method. DemoApp.java
public class DemoApp {
public static void main(String[] args) {
try {
Class cls=Wishes.class;
Method method1=cls.getDeclaredMethod("getGreeting");
String result1=(String) method1.invoke(cls.newInstance());
System.out.println(result1);
Class clazz=Day.class;
Method method=clazz.getDeclaredMethod("getWishes().getGreeting");
String result=(String) method.invoke(clazz.newInstance());
System.out.println(result);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
}
I run the application. For the first one I am getting exact output as it's straight forward. But for the second I am getting exception. Here is the console output and stacktrace.
Good Afternoon!
java.lang.NoSuchMethodException: com.myapp.demo.Day.getWishes().getGreeting()
at java.lang.Class.getDeclaredMethod(Class.java:2004)
at com.myapp.demo.DemoApp.main(DemoApp.java:17)
How to call the getGreeting method from getWishes from using Day class with Method reflect? Is it possible? Otherwise what is the best way to do that with method reflect?
In my application, the method name I am getting is from one XML file. So it may contain single method or sequence of method calls like the above.
first of all in Day class you should initiate wishes
private Wishes wishes = new Wishes();
second you need to this:
Method method=clazz.getDeclaredMethod("getWishes");
Object result= method.invoke(clazz.newInstance());
Method method2=result.getClass().getDeclaredMethod("getGreeting");
String result2=(String) method2.invoke(cls.newInstance());
System.out.println(result2);
The method Class#getDeclaredMethod takes the name of a method and the types of its parameters. You are handing the string getWishes().getGreeting what is not a valid method name. You want to use
Method method = clazz.getDeclaredMethod("getWishes");
what should work in order to get the instance of Wishes from your Day instance. For the received instance, you can then call the getGreeting method reflectively. Method chaining as you suggest it does not work with reflection. There are however libraries easing the reflection API as for example for bean access of chained properties. For your learning purposes, you however need to chain the reflective calls manually.
Reflective calls are not stacked. So the way you are calling the method getGreeting doesn't work.
You can try this way instead:
Class cls=Wishes.class;
Method method1=cls.getDeclaredMethod("getGreeting");
String result1=(String) method1.invoke(cls.newInstance());
System.out.println(result1);
Class clazz=Day.class;
Object ob = clazz.newInstance();
Method method2=clazz.getDeclaredMethod("setWishes", cls);
method2.invoke(ob, cls.newInstance());
Method method=clazz.getDeclaredMethod("getWishes");
Object day =(Object) method.invoke(ob);
System.out.println(((Wishes)day).getGreeting());
Note: This snippet can further be refactored to suit your requirements
There is no such method "getWishes().getGreeting" on the Day class. what you have to do is.
invoke "Day.getWishes() and get the output
on top of the above output object invoke getGreeting
On sequences you have to execute one by one.
By the way, I think it is worth having a look at JXPath library as an alternative.
you can give a complex object and do a xpath search.
Reflection calls don't stack - there is no method with the name "getWishes().getGreeting()" in class Day.
You need to first call "Day.getWishes()" and then call "getGreeting()" on the returned object.
In order to schedule the execution of a job, i get the name of a class as a string-input.
This class may be in one of two packages, but i don't know which one so i have to check this.
By now, i have two try-catch-blocks
Class<Job> clazz;
String className; //the above mentioned string, will be initialized
try {
clazz = (Class<Job>) Class.forName("package.one." + className);
} catch (ClassNotFoundException ex) {
try {
clazz = (Class<Job>) Class.forName("package.two." + className);
} catch (ClassNotFoundException ex1) {
//some error handling code here, as the class is
//in neither of the two packages
}
}
For more packages this will get uglier and more unreadable. Furthermore, it is - for me - against the concept of exceptions, as exceptions should'nt be expected/used for flow-control!
Is there any way to rewrite this without the utilization of the ClassNotFoundException?
I'd stick to the Class.forName method for that.
You can store the class and package names in Collections or Sets and loop through those elements. When you get a ClassNotFoundException, you just continue your search. If you don't get an exception, you exit the loop using break, as you have found the class you were looking for.
The reason I'd go for Class.forName is that it loads the class for you if it had not been already loaded by the VM. This is quite a powerful side effect.
It basically relieves you of the trouble of digging through the whole CLASSPATH and looking for class files to load in the VM and dealing with issues such as whether the class has already been loaded or not by the VM.
EDIT:
Jakob Jenkov has written some really great articles/tutorials on Java. I've found them extremely useful when dealing with reflection, class loaders and concurrency (some of the "hardest" aspects of Java).
Here's a good article on the Java class loader by him, for if you still decide not to use Class.forName.
public Class<Job> getClass(String className) {
String packages[] = { "package.one.", "package.two." };
for (int j = 0; j < packages.length; j++) {
try {
return (Class<Job>) Class.forName(packages[j] + className);
} catch (ClassNotFoundException ex) {
System.out.println("Package "+packages[j]+" is not worked");
}
}
return null;
}
You can use Guava's Reflection utilities to get the ClassInfo of every class loaded in the classpath.
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
ClassPath classPath = ClassPath.from(classLoader);
ImmutableSet<ClassInfo> set = classPath.getTopLevelClasses();
for (ClassInfo ci : set) {
System.out.println(ci.getName());
}
In the loop you can implement your custom logic to load the class with the className you're providing.
In this case, I wouldn't worry about using the ClassNotFoundException. While in general a case can be made to not use exceptions for flow control, here it hardly counts as such.
I'd probably wrap it in a function, like so
public static String getPackageForClass(String className, String... packageNames) {
for (String packageName : packageNames) {
try {
Class.forName(packageName + className);
return packageName;
} catch (ClassNotFoundException ignored) {
}
}
return "";
}
or return the class directly, if you so wish
public static Class getPackageForClass(String className, String... packageNames) {
for (String packageName : packageNames) {
try {
return Class.forName(packageName + className);
} catch (ClassNotFoundException ignored) {
}
}
return null;
}
Is there such a functionality in JAXB to perform operations on a class after it is unmarshalled i.e. after it is constructed by JAXB? If not, how could I achieve this?
You can use JAXB Unmarshal Event Callbacks which are defined in your JAXB class e.g:
// This method is called after all the properties (except IDREF) are unmarshalled for this object,
// but before this object is set to the parent object.
void afterUnmarshal( Unmarshaller u, Object parent )
{
System.out.println( "After unmarshal: " + this.state );
}
Though the the demanded functionality seems not to be present in JAXB, I managed to
achieve something which goes into the right direction:
I'm using JSR-305's #PostConstruct annotation
(it's just a nacked annotation, no functionality is provided by the JSR)
I add an unmasrshaller-listener to the unmarshaller, which gets invoked by JAXB every time an object was unmarshalled.
I inspect this object using Java reflection and search for the #PostConstruct annotation on a method
I execute the method
Tested. Works.
Here is the code. Sorry, I'm using some external reflection API to get all methods, but I think the idea is understandable:
Implementation
JAXBContext context = // create the context with desired classes
Unmarshaller unmarshaller = context.createUnmarshaller();
unmarshaller.setListener(new Unmarshaller.Listener() {
#Override
public void afterUnmarshal(Object object, Object arg1) {
System.out.println("unmarshalling finished on: " + object);
Class<?> type = object.getClass();
Method postConstructMethod = null;
for (Method m : ReflectionUtils.getAllMethods(type)) {
if (m.getAnnotation(PostConstruct.class) != null) {
if (postConstructMethod != null) {
throw new IllegalStateException(
"#PostConstruct used multiple times");
}
postConstructMethod = m;
}
}
if (postConstructMethod != null) {
System.out.println("invoking post construct: "
+ postConstructMethod.getName() + "()");
if (!Modifier.isFinal(postConstructMethod.getModifiers())) {
throw new IllegalArgumentException("post construct method ["
+ postConstructMethod.getName() + "] must be final");
}
try {
postConstructMethod.setAccessible(true); // thanks to skaffman
postConstructMethod.invoke(object);
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
} catch (InvocationTargetException ex) {
throw new RuntimeException(ex);
}
}
}
});
EDIT
Added a check for #PostConstruct-annotated method, to ensure it is final.
Do you think it's a useful restriction?
Usage
Here is how the concept might be used.
#XmlAccessorType(XmlAccessType.NONE)
public abstract class AbstractKeywordWithProps
extends KeywordCommand {
#XmlAnyElement
protected final List<Element> allElements = new LinkedList<Element>();
public AbstractKeywordWithProps() {
}
#PostConstruct
public final void postConstruct() {
// now, that "allElements" were successfully initialized,
// do something very important with them ;)
}
}
// further classes can be derived from this one. postConstruct still works!
Filed a feature request
https://jaxb.dev.java.net/issues/show_bug.cgi?id=698
It's not a 100% solution, but you can always register a XmlAdapter using #XmlJavaTypeAdapter annotation
for this type.
The downside would be that you have to serialize the class yourself (?). I am not aware of any simple way of accessing and calling the default serialization mechanism. But with custom [XmlAdapter] you can control how is the type serialized and what happens before/after it.