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?
Related
I am writing a unit test for my below code
public class Class1 {
protected void execute(String a, String b) {
try{
process(a,b);
}
catch(Exception E){
Class2.write(e,Class1.class.getSimpleName())
}
}
private void process(String a, String b) {
validate(a,b);
// Doing some processing on a and b values
}
private void validate (String a, String b) {
if(a==null || a.isEmpty() || b==null || b.isEmpty())
throw new IllegalArgumentException("Input value cannot be null or empty");
}
}
For the above code, I am trying to write a UT which covers the exception use case. Below is my UT code,
#Test
public void test1(){
try {
PowerMockito.mockStatic(Class2.class);
PowerMockito.when(Class2.class, "write", Mockito.anyObject(), Mockito.anyString())
.thenCallRealMethod();
Class1 class1 = new Class1();
Class2.write(new IllegalArgumentException("Input value cannot be null or empty"),Class1.class.getSimpleClassName());
PowerMockito.verifyStatic(Class2.class, VerificationModeFactory.times(1));
class1.execute(Mockito.anyString(),Mockito.anyString());
} catch (Exception e) {
e.printStackTrace();
Assert.fail(e.getMessage());
}
}
I am getting the below exception when I execute the above test
Argument(s) are different! Wanted:
Class2.write{
java.lang.IllegalArgumentException:Input value cannot be null or empty,
Class1
}
Actual invocation has different arguments:
Class2.write{
java.lang.IllegalArgumentException:Input value cannot be null or empty,
Class1
}
Can someone please help me on resolving this issue?
I really appreciate your help and time
Thanks in Advance
Your Problem:
IllegalArgumentException does not use the string message for equality. It would be safer to test the string message or the class type. I would prefer that the test detect the type rather than the message, as the string message should not be used for control flow, it is an implementation detail.
System.out.println(Objects.equals(
new IllegalArgumentException(),
new IllegalArgumentException()));
// false
System.out.println(Objects.equals(
new IllegalArgumentException().getClass(),
new IllegalArgumentException().getClass()));
// true
So to mock this I would use matchers:
any(IllegalArgumentException.class), eq(Class1.class.getSimpleName())
Issues with your design:
I'm going to end with an argument against how this code is structured, being that it is not built around dependency injection. Rather than calling the static method Class2::write, you could be calling an instance method.
For example, create the interface:
public interface Writer {
void write(Exception e, String source);
}
You can now refactor the class to provide two ctors, one that accepts any writer, and one that defaults to Class2.
public class Class1 {
private final Writer writer;
public Class1() {
this(Class2::write);
}
public Class1(Writer writer) {
this.writer = writer;
}
protected void execute(String a, String b) {
try {
process(a,b);
}
catch (Exception E) {
writer.write(e, Class1.class.getSimpleName());
}
}
...
}
Using this strategy you can now simply create an instance mock of Writer. This avoids having to mock as static method which changes the bytecode of your application, and also make your class more flexible as it can support many different writer implementations now. Anything that is modifying the bytecode of the application should be used very sparingly, such as replacing static method calls, does not truly validate the runtime execution of your code.
In my opinion, the majority of the PowerMockito/PowerMock only help verify code which was not built with testability / flexibility in mind. You shouldn't need to use anything outside of the Mockito/EasyMock tool-set for well structured code. There are some exceptions but the tool-set should be used very sparingly.
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.
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.
I m having a problem of calling a constructor with arguments from default constructor.
Class A {
private static Properties properties;
A(Properties property){
// do some checks
try{
load(property, fileName)
} catch(IOException e) {
throw new RuntimeException();
}
}
A(){
this(load(properties));
}
private static Properties load(Properties properties, String fileName ) throws IOException {
try {
properties.load(A.class.getClassLoader()
.getResourceAsStream(fileName));
} catch (IOException ioException) {
throw new IOException("Unable to process the properties File. " + fileName, ioException);
}
return properties;
}
}
My problem is: In Default constructor I wanted to use try/catch block and do the same operation of throwing a run time exception. Can you help me out as what can be done in this?
WRT this post: chaining constructors in Java without throwing exceptions from the default constructor
I have an option of putting try/catch inside another method. But is there any other way?
P.S: I do not want to use 'throws'
Java does not allow chained constructor calls to be enclosed within a try block, since such constructs could if not restricted allow an object whose base object threw an exception to end up being returned to calling code. This makes it difficult to express certain concepts involving resources like files [e.g. it would be helpful to have a constructor open a file before chaining to the parent and close it afterward, but there's no way to safely have a constructor take responsibility for a file which is opened before chaining to the parent]. The best one can do in Java is avoid public constructors which might throw exceptions and instead use factory methods which can be better equipped to handle them.
Option 1: Pass the other constructor a new empty instance of Properties:
class A
{
public A()
{
this(new Properties());
}
// rest of code...
}
Option 2: Pass the other constructor a null instance of Properties. You'll then have to guard against null in load(...), but you probably should be anyway:
class A
{
public A()
{
this(null);
}
// rest of code...
}
Option 3: Pass the other constructor a default instance of Properties:
class A
{
private static final Properties defaultProperties;
static
{
defaultProperties = new Properties();
// populate here however you wish
}
public A()
{
this(defaultProperties);
}
// rest of code...
}
I'm using Mockito and want to do a hopefully simple thing. How do I mock a void method for a particular class? I tried ...
CacheService cs = mock(CacheService.class);
when(cs.startCache()).then( PopulateCache.addTestEntriesToCache() );
But I'm getting the compile error
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:2.3.2:testCompile (default-testCompile) on project cme-productplus-web: Compilation failure: Compilation failure:
[ERROR] \Documents and Settings\E18538\workspace\cme-productplus-web\src\test\java\com\cme\clearing\product\server\PopulateCacheServiceImpl.java:[32,65] 'void' type not allowed here
[ERROR] \Documents and Settings\E18538\workspace\cme-productplus-web\src\test\java\com\cme\clearing\product\server\PopulateCacheServiceImpl.java:[32,20] 'void' type not allowed here
My intention is instead of calling the normal code of CacheService.startCache, I want to call my own method, "PopulateCache.addTestEntriesToCache()". How can I do this?
Edit: Per the response given, I tried editing my class where I implement the mock, but the mock method (the doAnswer, presumably) isn't getting called ...
public class PopulateCacheServiceImpl extends RemoteServiceServlet implements PopulateCacheService {
/**
*
*/
private static final long serialVersionUID = 1L;
public Boolean initCache() {
boolean ret = false;
try {
setupMockCache();
CacheService.getInstance().startCache();
ret = true;
} catch (Exception e) {
e.printStackTrace(System.err);
ret = false;
} // try
return ret;
} // initCache
private void setupMockCache() {
CacheService cs = mock(CacheService.class);
try {
doAnswer(new Answer<Object>() {
public Object answer(InvocationOnMock invocation) throws Throwable {
PopulateCache.addTestEntriesToCache();
return null;
}
}).when(cs).startCache();
} catch (SQLException e) {
e.printStackTrace();
}
} // setupMockCache
}
Thanks, - Dave
You are making a mock for the CacheService, but you are still not returning it and using it anywhere. Instead, you are calling the real static CacheService.instance() method which will not return your mock. Make you setupMockCache() return the CacheService and use it directly rather than going through the instance() method.
Also in the question title/summary, you said "leave everything else the same". If you mean you want the rest of CacheService to behave the same as it normaly would, then perhaps you want a partial mock, which you can do with Mockito's spy() instead of mock().
Put the call to your cache in the anwser-method of this http://docs.mockito.googlecode.com/hg/latest/org/mockito/Mockito.html#12
Mockito.doAnswer(new Answer<Object>() {
public Object answer(InvocationOnMock invocation) throws Throwable {
PopulateCache.addTestEntriesToCache()
return null;
}
}).when(cs).startCache();
Of course it doesn't work : in setupMockCache you are creating a the cache mock CacheService cs = mock(CacheService.class); on which you define the stub. But the cs instance is never passed.
And in initCache you are calling the setup method, but you don't get the CacheService instance, right after you wrote this statement CacheService.getInstance().startCache(); that will certainly create a real CacheService instance and fo course it won't use the mocked instance.
I don't know what you want to do, this seems weird and wrong to mock partially a Cache in your production code! If I were you I would create my own set of classes that will return your custom cache backed by an inherited CacheService class if necessary (this class will explicitly overide the startCache method).
Hope that helps!