Is it possible in Java, to get a Method object representing the method in which an exception was thrown provided nothing but said exception?
Given the example:
public class Test {
protected void toFail() throws Exception {
throw new Exception();
}
protected void toFail(String someparameter) throws Exception {
throw new Exception();
}
public static void main(String[] args) {
try {
new Test().toFail("");
}catch(Exception ex){
//Clever code here
}
}
}
What clever code would allow me to get a Method object representing the toFail(String) method? Assuming its even possible :)
Clarification:
I need to uniquely identify the method that caused the exception, and i need to be able to create a reflection Method object from it. When i say uniquely i mean that i need to take the possibility of overloaded methods into account.
You can get the name of the class and method it was thrown from like this:
StackTraceElement ste = exception.getStackTrace()[0];
String className = ste.getClassName();
String methodName = ste.getMethodName();
But you can't get the Method object because the StackTraceElement does not record which of the methods with the same name.
You can get the possible Method objects (possible as with matching name) like this:
StackTraceElement ste = exception.getStackTrace()[0];
Class<?> c = Class.forName(ste.getClassName());
String mname = ste.getMethodName();
// NOTE:
// Exceptions thrown in constructors have a method name of "<init>"
// Exceptions thrown in static initialization blocks have a method name of
// "<cinit>"
if ("<init>".equals(mname)) {
// Constructors are the possible "methods", all of these:
c.getConstructors();
} else if ("<cinit>".equals(mname)) {
System.out.println("Thrown in a static initialization block!");
} else {
// Thrown from a method:
for (Method m : c.getMethods()) {
if (m.getName().equals(mname)) {
System.out.println("Possible method: " + m);
}
}
}
Use StackTrace() for this.
public class Test {
protected void toFail(String someparameter) throws Exception {
throw new Exception();
}
public static void main(String[] args) {
try {
new Test().toFail("");
}catch(Exception ex){
StackTraceElement[] stl = ex.getStackTrace();
System.out.println(stl[0].getMethodName());
}
}
}
Related
I have below piece of code in my spring boot app, which validates email addresses
class EmailValidation {
public static void validate(List<String> s){
try {
for (String address : s) {
if (s == null || s.indexOf("#") < 0) {
throw new InvalidEmailAddressException("Email address is invalid ");
}
new InternetAddress(s);
}
} catch(AddressException e){
LOGGER.Error("Please validate email addresses");
}
catch(InvalidEmailAddressesException e){
LOGGER.error(e.getMessage());
}
}
class InvalidEmailAddressException extends Exception {
public InvalidEmailAddressException(String message) {
super(message)
}
}
}
I want to write a Junit test which will verify that that InvalidEmailAddressesException was thrown and CAUGHT. How can I do that in JUnit?
In general I agree with the comments that such a test is probably unnecessary.
However, if I wanted to test something like that I would test the two cases separately and that requires a small modification to your code.
Firstly I would construct a method that only throws the exception if there is one.
public static void checkAddresses(List<String> s) throws AddressException, InvalidEmailAddressException {
for (String address : s) {
if (s == null || s.indexOf("#") < 0) {
throw new InvalidEmailAddressException("Email address is invalid ");
}
new InternetAddress(s);
}
}
then I would use it in your code like that:
class EmailValidation {
public static void validate(List<String> s){
try {
checkAddresses(s); // a wrapper method that throws the expected exceptions
} catch(AddressException e){
LOGGER.Error("Please validate email addresses");
}
catch(InvalidEmailAddressesException e){
LOGGER.error(e.getMessage());
}
}
// add checkAddresses here or somewhere appropriately
class InvalidEmailAddressException extends Exception {
public InvalidEmailAddressException(String message) {
super(message)
}
}
}
Then, I would write separate tests for checkAddresses that tests both if an exception is expected or not and separate tests for validate, (possibly with the same input that was given to checkAddresses) that should pass if an exception isn't thrown.
Also, if you would like to verify your logs may be you could try something like that.
Indeed using java Exception for common cause is considered a bad practice, and as #Michael said, Exceptions must be exceptional, because
they break flow control
they are slow (more details here How slow are Java exceptions?)
they do not mix with functional paradigm (where Java is in part going to with the addition of lamda-expressions
However, creating a custom object for wrapping validation data is a good thing and InvalidEmailAddressException can be turned into CheckedEmail:
import java.util.List;
import java.util.stream.Collectors;
public class EmailValidator {
public List<CheckedEmail> validate(List<String> emailAddresses) {
return emailAddresses.stream().map(this::validate).collect(Collectors.toList());
}
public CheckedEmail validate(String emailAddress) {
String[] emailParts = emailAddress.toString().split( "#", 3 );
final boolean valid;
if ( emailParts.length != 2 ) {
valid = false;
} else {
// More validation can go here using one or more regex
valid = true;
}
return new CheckedEmail(emailAddress, valid);
}
public static final class CheckedEmail {
private final String emailAddress;
private final boolean valid;
private CheckedEmail(String emailAddress, boolean valid) {
this.emailAddress = emailAddress;
this.valid = valid;
}
public String getEmailAddress() {
return emailAddress;
}
public boolean isValid() {
return valid;
}
}
}
This in turn can be tested quite easily (and improved with a parameterized test):
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
public class EmailValidatorTest {
private final EmailValidator emailValidator = new EmailValidator();
#Test
public void invalid_email() {
EmailValidator.CheckedEmail checkedEmail = emailValidator.validate("missing.an.at.symbol");
assertThat(checkedEmail.isValid()).isFalse();
}
#Test
public void valid_email() {
EmailValidator.CheckedEmail checkedEmail = emailValidator.validate("at.symbol#present");
assertThat(checkedEmail.isValid()).isTrue();
}
#Test
public void multiple_email_addresses() {
List<String> emailAddresses = Arrays.asList("missing.an.at.symbol", "at.symbol#present");
List<EmailValidator.CheckedEmail> checkedEmails = emailValidator.validate(emailAddresses);
assertThat(checkedEmails)
.extracting(ce -> ce.getEmailAddress() + " " + ce.isValid())
.containsExactly(
"missing.an.at.symbol false",
"at.symbol#present true");
}
}
If somewhere the point is just to log this, then:
List<EmailValidator.CheckedEmail> checkedEmails = emailValidator.validate(emailAddresses);
checkedEmails.stream()
.filter(ce -> !ce.isValid())
.map(ce -> String.format("Email address [%s] is invalid", ce.getEmailAddress()))
.forEach(logger::error);
Hope this helps !
Don't approach testing that way. You should test only the specified behaviour of your code, not its implementation details.
If the method you are testing delegates to a method that throws a checked exception, and the method you are testing does not also declare that it throws that checked exception, the compiler will enforce that the method catches the exception. So in that case a unit test is unnecessary.
If the method you are testing delegates to a method that throws an unchecked exception, consult the specification of the method to determine whether it is acceptable for the method under test to also throw (propagate) that exception. If it is not acceptable for it to propagate the exception, then you should create a test case that causes the the method delegated to to throw that unchecked exception. If the method propagates the exception, the test case will fail. How to do that? That depends on the method being delegated to, but in most cases you will need to use Dependency Injection to supply a mock object that throws the exception.
I have a class like this
parent class DevPortalTestController is absract
public class SeleniumWebDriverFactory extends DevPortalTestController {
public static RemoteWebDriver mDriver;
public SeleniumWebDriverFactory(RemoteWebDriver whichDriver)throws UnsupportedOSException, PoisonException {
super(whichDriver);
mDriver = whichDriver;
}
public List<TestContext> getBrowserTestContext(List<String> browsers)
throws Exception {
PhoenixDriver driver = null;
List<TestContext> contexts = new ArrayList<TestContext>();
logger.info("Setting browser context...");
Login login = retrieveLoginData();
for (String browser : browsers) {
// operations
Map<String, Object> browserMap = new HashMap<String, Object>();
// Populate the map with DevPortalTestController objects.
browserMap.put(MasterConstants.BROWSER, this);
.....
.....
}
return contexts;
}
public static List<TestContext> getTestContext(List<String> browsers)
throws Exception {
SeleniumWebDriverFactory instanceSel = new SeleniumWebDriverFactory(mDriver);
List<TestContext> contexts = instanceSel.getBrowserTestContext(browsers);
return contexts;
}
}
I need to call this getTestContext method in another class
for that am doing like this.Also that class is extenting another parnet class
public class DevPortalTest extends Test {
RemoteWebDriver rmDriver ;
SeleniumWebDriverFactory selFac =new SeleniumWebDriverFactory(rmDriver);
#Override
public List<TestContext> getTestContexts() {
try {
String os = System.getProperty("os.name");
if (SystemDetail.deviceIsRunningWindows()) {
return selFac.getTestContext(ZucchiniConstants.allBrowsers);
else {
throw new TestException(os + " is not supported");
}
} catch (Exception e) {
logger.error("", e);
}
return null;
}
}
But in this place
SeleniumWebDriverFactory selFac =new SeleniumWebDriverFactory(rmDriver);
I'm getting
Default constructor cannot handle exception type PoisonException
thrown by implicit super constructor. Must define an explicit
constructor
How can i call the method getTestContext inside DevPortalTest test class?
The problem is that initializer code will be placed in the "default constructor" which cannot throw any exception. Define an empty constructor that throws the exceptions to proceed.
e.g.,
DevPortalTest() throws UnsupportedOSException, PoisonException { }
You have to add the constructor to your test code:
public DevPortalTest() throws UnsupportedOSException, PoisonException {
SeleniumWebDriverFactory selFac = new SeleniumWebDriverFactory(rmDriver);
}
also, i assume you're injecting RemoteWebDriver rmDriver;
Since the method is static, you don't need an object to call it.
SeleniumWebDriverFactory.getTestContext(ZucchiniConstants.allBrowsers);
As an alternative to creating a constructor you can also do this
public class DevPortalTest extends Test {
RemoteWebDriver rmDriver ;
SeleniumWebDriverFactory selFac;
// this code block runs before constructor
{
try{
selFac = new SeleniumWebDriverFactory(rmDriver);
}catch(Exception e){
// handle exception
}
}
Static method can be accessed using class Name so there is no need to create any Object in Abstract class.
The following code does not compile ("variable name might not have been initialized"):
import javax.management.*;
public class Main {
public final static ObjectName name;
static {
try {
name = new ObjectName("abc");
} catch (final Exception e) {
System.exit(1);
}
}
}
However, the following code does not compile either ("variable name might already have been assigned"):
import javax.management.*;
public class Main {
public final static ObjectName name;
static {
try {
name = new ObjectName("abc");
} catch (final Exception e) {
name = null;
System.exit(1);
}
}
}
I do not think the compiler is right about the either case, but anyways how are we supposed to initialize a static final ObjectName?
The first line of advice is don't call System.exit(). It causes the application to suddenly quit, without normal cleanup.
If you absolutely must exit the application at that precise point, then your workaround is to add
throw e;
after your System.exit() call.
If you're curious about the compiler error, you may be interested to read about it in this question.
The compiler expects that, in all possible branches of execution within your static initializer block, that ObjectName is assigned a value.
In
static {
try {
name = new ObjectName("abc");
} catch (final Exception e) {
System.exit(1);
}
}
Since ObjectName is not assigned a value in the catch-block, and since no exception is thrown, the compiler does not allow it.
If there were an exception thrown in the catch block, it would be acceptable.
An alternative method to implementing static initializer blocks, which I prefer, is where the block is a simple call to a private static function:
static {
init();
}
private static init() {
//do stuff
}
Just use a private static method instead of the static initializer:
private static final ObjectName name = initObjectName();
private static ObjectName initObjectName() {
try {
return new ObjectName("abc");
} catch (MalformedObjectNameException e) {
return null;
}
}
I have the following code which allows me to input in the scanner the Employee getter method that I want to call and it will do it using reflection (the name of the method should not appear anywhere in the code). This works for getter methods but I now need to modify the code to do something similar for setter methods. I have been trying to figure how to do it for the past week but I have been unable. Any help would be appreciated.
Thanks.
public static void main(String[] args) {
Employee e = Employee.testEmployee(); // a sample employee
Class cls = e.getClass();
Scanner scanner = new Scanner (System.in); // to parse data the user types in
String nextCommand;
// until the user enters "quit", get the next input from the user, and if it matches
// a given command, get the desired information from the employee object
do {
System.out.print("Enter command >> ");
nextCommand = scanner.next();
Method method = null;
try{
method = cls.getMethod(nextCommand);
}
catch(NoSuchMethodException x) {
}
try{
System.out.println(method.invoke(e));
}
catch(IllegalAccessException x) {
}
catch(java.lang.reflect.InvocationTargetException x) {
}
catch(NullPointerException x) {
}
} while (! nextCommand.equals("quit"));
}
Here's a code sample that does what you want to achieve:
public class Test {
private static HashSet<Class<?>> classes = new HashSet<>();
static {
classes.add(String.class);
classes.add(Integer.class);
classes.add(GregorianCalendar.class);
}
public static void main(String[] args) throws NoSuchMethodException,
SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
X obj = new X();
obj.setField("lala");
Method method = obj.getClass().getMethod("getField", null);
System.out.println(method.invoke(obj, null));
Method setMethod = getWorkingMethod(obj);
setMethod.invoke(obj, "who let the dogs out");
System.out.println(obj.getField());
}
private static Method getWorkingMethod(Object obj) {
Method method = null;
for (Class<?> c : classes) {
try {
method = obj.getClass().getMethod("setField", c);
} catch (NoSuchMethodException | SecurityException e) {
continue;
}
if(method != null){
return method;
}
}
throw new IllegalArgumentException("No such method found!");
}
}
class X {
private String stringField;
public void setField(String s) {
stringField = s;
}
public String getField() {
return stringField;
}
}
Output:
lala
who let the dogs out
Notes:
Create a collection (I used a HashSet) that stores Class<?> objects. You will use these to iterate over the possibilities and see if a method with that argument exists.
Use a try-catch to see if the method exists (an exception is thrown when it can't find it).
This will not work for overloaded methods. If this is your scenario, you'll have to make adjustments. I expect it to be no problem though, since you said this was meant for setters (which typically don't have overloads).
You can avoid calling the getter and setter methods by directly accessing the Field through reflection.
The Field object has various get and set methods that can be used to manipulate field values.
See: http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getField%28java.lang.String%29
EXAMPLE
import java.lang.reflect.Field;
public class MyObject {
private String fieldA;
public String getFieldA() {
return fieldA;
}
public void setFieldA(String fieldA) {
this.fieldA = fieldA;
}
public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
MyObject myObject = new MyObject();
myObject.setFieldA("Test");
Class clazz = myObject.getClass();
Field field = clazz.getDeclaredField("fieldA");
field.setAccessible(true);
String fieldA = (String) field.get(myObject);
System.out.println(fieldA);
field.set(myObject, "Test2");
fieldA = (String) field.get(myObject);
System.out.println(fieldA);
field.setAccessible(false); //be sure to return field to private
}
}
Resolution (method or field resolution) in java slows down you execution time by 'orders of 10 or 100', hence not a smart design decision. So, resolve once at start time, cache method instance, and execute it from cache. Avoid frequent lookups using reflection.
it's been quite a few months that i quite Java in favor of Python. Now i'm go back to java to project constraints.
now, i'm wondering if there's a way to get all the aprameters (with values) of a functions programmatically inside the function itself.
something like this
public void foo(String arg1,String arg2, Integer arg3){
... pars = ...getpars();
}
foo("abc","dfg",123);
where getpars() should return an HashMap with name,value pairs.
so from the example should be
arg1,"abc"
arg2,"dfg"
arg3,123
is there anything like this?
Unfortunately this is impossible. The only thing you can do is to retrieve the list of parameters types of a particular method using reflection.
But there is no way to get a map with name -> value of each argument passed into the method itself.
You can't get the name of the parameter, because it's no value just a name. If you wanna have the name of the parameter in your Map define a String which matches your parameter name and put it in.
Read this similar question. The accepted answer seems to have a solution for this using a third party library.
You can't get the names of the parameters dynamically, nor can you find the values in any way other than using the variable names. However, JAVA has the next best thing: variable arguments. If you want to have a dynamic number of arguments, you can declare your method as follows:
public void foo(Object... args)
When you call the method, you will call it with any number of arguments; foo(1, 2, "ABC") and foo(new File("config.dat"), new Scanner(), 88.5D) are both valid calls. Inside the function, args will be an array containing all of the parameters in order.
Just a few usage tips, though. The method declaration above is, in general, not considered good form. Usually, you can be much more specific. Think hard about whether or not you need all this flexibility, and consider using a few overloaded methods or possibly passing a HashMap to the function instead. Very rarely will you actually need to have dynamic parameters in that broad of a sense.
You could use:
void foo(String... args) {
for (String arg: args) { }
for (int i = 0; i < args.length - 1; i += 2) {
map.put(args[i], args[i + 1];
}
}
foo("a", "1", "b", "2");
Or use a Map builder, see builder-for-hashmap.
There are some hacky ways of getting the parameters values of an invoked method (But you have to understand that the parameters are unnamed, the best you can do is to get arg0.... argN).
Use Proxies
Aspect oriented programming (AspectJ, Spring AOP)
Let's consider the 1st approach. Say we want to log parameters before executing the method of some interface MethodParamsInterface, here you go. If you want to use these arguments in your logic - consider to implement them in InvocationHandler (or use EasyMock instead)
interface MethodParamsInterface {
void simpleMethod(int parm1, int parm2);
void simpleMethod(int parm1, int parm2, int param3);
}
public class MethodParams implements MethodParamsInterface {
public void simpleMethod(int parm1, int parm2) {
//business logic to be put there
}
public void simpleMethod(int parm1, int parm2, int param3) {
//business logic to be put there
}
public MethodParamsInterface wrappedInstance() throws Exception {
Class<?> proxyClass = Proxy.getProxyClass(MethodParams.class.getClassLoader(), MethodParamsInterface.class);
InvocationHandler invocationHandler = new InvocationHandler() {
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Map<String, Object> params = new LinkedHashMap<String, Object>(args.length);
for (int i = 0; i < args.length; i++)
params.put("arg" + i, args[i]);
//printing out the parameters:
for (Map.Entry<String, Object> paramValue : params.entrySet()) {
System.out.println(paramValue.getKey() + " : " + paramValue.getValue());
}
return MethodParams.this.getClass().getMethod(method.getName(), method.getParameterTypes()).invoke(MethodParams.this, args);
}
};
return (MethodParamsInterface) proxyClass.getConstructor(new Class[]{InvocationHandler.class}).newInstance(invocationHandler);
}
public static void main(String[] args) throws Exception {
MethodParams instance = new MethodParams();
MethodParamsInterface wrapped = instance.wrappedInstance();
System.out.println("First method call: ");
wrapped.simpleMethod(10, 20);
System.out.println("Another method call: ");
wrapped.simpleMethod(10, 20, 30);
}
}
import javassist.util.proxy.MethodFilter;
import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.ProxyFactory;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
class Test01 {
public int method01(int i, int j) {
System.out.println("Original method01");
return i + j;
}
}
class ParameterWriter {
public static <T> T getObject(T inp) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
ProxyFactory factory = new ProxyFactory();
factory.setSuperclass(inp.getClass());
factory.setFilter(
new MethodFilter() {
#Override
public boolean isHandled(Method method) {
return true;
}
}
);
MethodHandler handler = new MethodHandler() {
#Override
public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable {
for (int i = 0; i < args.length; i++) {
System.out.println(proceed.getParameters()[i].getName() + ":" + args[i]);
}
return proceed.invoke(self, args);
}
};
return (T) factory.create(new Class<?>[0], new Object[0], handler);
}
}
public class Main {
public static void main(String[] args) {
try {
Test01 test01 = ParameterWriter.getObject(new Test01());
test01.method01(2, 3);
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
output:
arg0:2
arg1:3
Original method01