Background:
I have hundreds of XXXFaultMsg classes generated from a WSDL file, they all have a method getFaultMsg() but they are extended from Exception directly. I have a function with argument Exception e, where e might be instance of one of the XXXFaultMsg classes.
Challenge:
I want to invoke getFaultMsg() on e if it is an instance of XXXFaultMsg.
I have written if (e.getClass().getName().endsWith("FaultMsg")) to detect whether e is an instance of XXXFaultMsg. Then how can I declare a var with type XXXFaultMsg and cast e to it and call getFaultMsg() on it?
P.S. I don't want to construct a long list of if (e instanceof XXXFaultMsg) cause there are over 100 XXXFaultMsg classes.
Say you have one method which takes no args:
Method methodToFind = null;
if (e.getClass().getName().endsWith("FaultMsg")){
try {
methodToFind = e.getClass().getMethod("getFaultMsg", (Class<?>[]) null);
} catch (NoSuchMethodException | SecurityException e) {
// Your exception handling goes here
}
}
Invoke it if present:
if(methodToFind == null) {
// Method not found.
} else {
// Method found. You can invoke the method like
methodToFind.invoke(e, (Object[]) null);
}
Related
The sample function catches checked Exceptions A and B and throws A.
I expected the if statement with instanceof to unwind the union to the expected type, however I still need to cast it.
Is there a reason Java's type system can't/doesn't unwind the union type with instanceof?
public static void throwsA() throws ExceptionA {
try {
funThatThrowsAorB();
} catch (ExceptionA | ExceptionB e) {
// common code
if (e instanceof ExceptionA) {
throw e; // unhandled exception error
throw (ExceptionA)e; // no problem
} else {
throw new ExceptionA(e);
}
}
}
The Java language never narrows a type when entering an if-statement (or any other conditional).
However, Java 14 introduced pattern matching for instanceof expressions as a preview feature:
if (obj instanceof String s) {
// can use s here
} else {
// can't use s here
}
As you can see, this introduces a new variable with the narrowed type, rather than narrowing the type of the existing variable. I am not certain why they chose that route, but I suspect backwards compatibility played a role. Specifically, if you simply narrow the type of an existing variable when entering a conditional, it might break existing code such as the following program:
Number number = 42;
if (number instanceof Integer) {
number = 0.01 * number;
}
To fix that, you'd need to change the type of the variable not just when entering a conditional, but on any assignment. That's more complicated, but TypeScript shows that this is possible:
let x: number | string = "23";
if (typeof x === "string") {
x.charAt(0); // x is a string here
x = 3;
x.toPrecision(2); // but a number here
}
I don't know why the Java design team disliked the TypeScript approach.
Because when you are inside of the catch block, e is an instance of a capture type for both exceptions A and B. By casting, you are specifying that you are throwing ExceptionA specifically:
//e is an "instanceof" either ExceptionA or ExceptionB, but not specified yet!
//For now, e is simply the most specific shared parent type (Exception I assume)
ExceptionA eA; //Cannot be set to e! Cannot coerce Exception into ExceptionA
if (e instanceof ExceptionA) {
eA = (ExceptionA) e; //Have to explicitly cast
throw eA;
}
This works, because your method is specified to be capable of only throwing ExceptionA:
public static void throwsA() throws ExceptionA { ...
As far as why this is required, the error message from attempting an assignment is also pretty clear:
#Andreas offers a much more clear solution, which is just directly handling these errors individually:
try {
//A or B exceptional code
} catch (ExceptionA eA) {
throw eA;
} catch (ExceptionB eB) {
//... B handling
}
System.out.println(GraphController.GRAPHPOOL.peek().getEdge());
Stream.generate(() -> {
try {
return GraphController.GRAPHPOOL.take();
} catch (InterruptedException ie) {
return "Interrupted!";
}
})
.forEach(g -> {System.out.println(g.getEdge());}
});
I am able to print the object Edge returned by getEdge out of Stream.generate().forEach(), however, within forEach I can access only object g.
When trying to access g.getEdge() I get an error as follows:
error: cannot find symbol
System.out.println(g.getEdge());
symbol: method getEdge()
location: variable g of type Object
How can I access g.getEdge()?
due to the call GraphController.GRAPHPOOL.take(); returning a different type to the statement return "Interrupted!", the elements returned by the generate intermediate method will all be of type Object and there is no such method called getEdge() within the Object class. To overcome the problem you can do something like:
.forEach(g -> {
if(g instanceof TheType){
System.out.println(((TheType)g).getEdge());
}
else{
// "interrupted"
}
});
Also, note that the method generate(Supplier<T> s) returns an infinite sequential stream, usually in cases like this you'll want to utilize limit to truncate the stream.
You have to cast your g to the wished datatype. As you can read, the variable g is currently an Object. Simply cast it with (neededObjectforGetEdge(g)).getEdge()
In code we have got a lot of chain methods, for example obj.getA().getB().getC().getD(). I want to create helper class which will check if method getD() isn't null, but before that I need to check all previous getters. I can do it in this way:
try {
obj.getA().getB().getC().getD();
}
catch (NullPointerException e) {
// some getter is null
}
or (which is "silly")
if (obj!null && obj.getA()!=null && obj.getA().getB()!=null && ...) {
obj.getA().getB().getC().getD();
}
else {
// some getter is null
}
I don't want to check it every time using try{} catch() in my code. What is the best solution for this purpose?
I think that the best will be:
obj.getA().getB().getC().getD().isNull() - for this purpose I will need to change all of my getters, for example implement some interface which contains isNull() method.
NullObjectHelper.isNull(obj.getA().getB().getC().getD()); - this will be the best (I think so) but how to implement this?
As of Java 8 you can use methods like Optional.isPresent and Optional.orElse to handle null in getter chains:
boolean dNotNull = Optional.ofNullable(obj)
.map(Obj::getA)
.map(A::getB)
.map(B::getC)
.map(C::getD)
.isPresent();
While this is preferable to catching NullPointerException the downside of this approach is the object allocations for Optional instances.
It is possible to write your own static methods that perform similar operations without this overhead:
boolean dNotNull = Nulls.isNotNull(obj, Obj::getA, A::getB, B::getC, C::getD);
For a sample implementation, see the Nullifier type here.
No approach is likely to have greater runtime efficiency than nested if-not-null checks.
You can achieve the desired result with Option pattern. This enforces you to change a method signature, but basically if your method returns some type T, it guarantees it has some non-null value, and if it returnsOption<T> it means it either has value T, or null.
Java 7 had some feature called null safety, but it was removed from the final release. You could do:
obj?.getA()?.getB()?.getC()?.getD()
Moreover, Java 8 will add a feature called Optional so you would do it safely.
In fact, if you really want to use that now, try Null Object pattern. It means that instead of returning plain null you can return some sort of default value, which won't trigger NullPointerException. Though, you need add some changes to your getters
class Object {
A getA() {
// ...
return a == null ? A.NULL : a;
}
}
class A {
static A NULL = new A(); // some default behaviour
B getB() {
if (this == NULL) return B.NULL;
// ...
return b == null ? B.NULL : b;
}
}
EDIT: If you want utility to do it you can wrap it in some functional interface and then call it.
static boolean isNullResult(Callable call) throws Exception {
try {
return call.call() == null;
} catch (NullPointerException npe) {
return true;
}
}
Usage will be the following:
isNullResult(new Callable<Integer>() {
#Override
public Integer call() throws Exception {
return new A().getB().getC().getInt();
}
});
It won't require you to change existing functionality
As already stated, the true solution is refactoring.
In the meantime, you could just wrap your first workaround in a function:
static D getD(MyClass obj) {
try {
return obj.getA().getB().getC().getD();
}
catch (NullPointerException e) {
return null; // Or even better, some default D
}
}
At the caller site:
D d = getD(obj);
At least you don't have to trash the caller with try-catch blocks. You still need to handle the errors somehow, when some of the intermediate getX() call returns a null and so d becomes null. The best would be to return some default D in the wrapper function.
I don't see how the two options you list at the end of your question would help if any of the intermediate getX() returns a null; you will get a NullPointerException.
Two questions regarding the MethodHandle class:
Is it true that every call to invokeExact() requires type casting of the return value (except for target methods that return void or Object) ?
It seems that a MethodHandle can only be bound once to a receiver. Given an arbitrary MethodHandle instance, is there any way to determine whether it has already been bound and if so, to what type?
public static void main(String[] args) throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.publicLookup();
MethodHandle handle = lookup.bind(new Object(), "toString", MethodType.methodType(String.class));
String s = (String) handle.invokeExact();
System.out.println(s);
try {
handle.invokeExact();
}
catch (WrongMethodTypeException e) {
System.out.println(e);
}
try {
handle.bindTo(new Object());
}
catch (IllegalArgumentException e) {
System.out.println(e);
}
}
You can call bindTo multiple times, but you should not. The implementation assumes you want to set the receiver, if you start using this to also set arguments you produce a more complicated handle, that is more difficult to compile into lambda forms and then potentially less efficient. I advise using MethodHandles#insertArguments instead
I have an xml schema (generated automatically using trang) which keeps changing. These changes are not very elaborate. Only some elements are added or deleted from this schema. From this schema, I am generating java classes (using cxf) by which I will unmarshall the xml document.
As schema changes, my auto-generated java classes also change. Again, as with schema, changes in java classes are not very big. For instance, if an element say elemA is added to schema; some related functions say getElemA() and setElemA() are added to auto-generated java class.
Now how would I make sure that a particular function exists in these auto-generated classes? One solution is to hand-write the schema such that all possible elements of xml are covered. This is what I'll ultimately do. But for now, I have not fixed the format of xml file.
UPDATE :
There is a possibility that a method getElemA() may be defined in auto-generated classes. I do not have control over the auto-generation of these classes. But in my main class, if have following code,
If method getElemA exists then
ElemA elemA = getElemA()
This code will always be there in my main class. If method getElemA() is generated in one of the auto-generated class then there is no problem. But if this method is not generated then compilers complain that this method does not exists in any of the class.
Is there any way that I can make compiler not to complain about this function at compile time?
One method is mentioned by #missingfaktor and another is below (if you know the name and parameters of the api).
Say you have one method which takes no args:
Method methodToFind = null;
try {
methodToFind = YouClassName.class.getMethod("myMethodToFind", (Class<?>[]) null);
} catch (NoSuchMethodException | SecurityException e) {
// Your exception handling goes here
}
Invoke it if present:
if(methodToFind == null) {
// Method not found.
} else {
// Method found. You can invoke the method like
methodToFind.invoke(<object_on_which_to_call_the_method>, (Object[]) null);
}
Say you have one method which takes native int args:
Method methodToFind = null;
methodToFind = YouClassName.class.getMethod("myMethodToFind", new Class[] { int.class });
Invoke it if present:
if(methodToFind == null) {
// Method not found.
} else {
// Method found. You can invoke the method like
methodToFind.invoke(<object_on_which_to_call_the_method>, invoke(this,
Integer.valueOf(10)));
}
Say you have one method which takes boxed Integer args:
Method methodToFind = null;
methodToFind = YouClassName.class.getMethod("myMethodToFind", new Class[] { Integer.class });
Invoke it if present:
if(methodToFind == null) {
// Method not found.
} else {
// Method found. You can invoke the method like
methodToFind.invoke(<object_on_which_to_call_the_method>, invoke(this,
Integer.valueOf(10)));
}
Using the above soln to invoke method won't give you compilation errors.
Updated as per #Foumpie
Use reflection.
import java.lang.reflect.Method;
boolean hasMethod = false;
Method[] methods = foo.getClass().getMethods();
for (Method m : methods) {
if (m.getName().equals(someString)) {
hasMethod = true;
break;
}
}
Edit:
So you want to invoke the method if it exists. This is how you do it:
if (m.getName().equals(someString)) {
try {
Object result = m.invoke(instance, argumentsArray);
// Do whatever you want with the result.
} catch (Exception ex) { // For simplicity's sake, I am using Exception.
// You should be handling all the possible exceptions
// separately.
// Handle exception.
}
}
With Spring:
Method method = ReflectionUtils.findMethod(TheClass, "methodName");
if (method != null) {
//do what you want
}
If you use Spring Framework, the simplest way would be to use ReflectionUtils.findMethod() utility.
Another way is by using Java 8 stream:
Optional<Method> methodToFind =
Arrays.stream(clazz.getMethods()).
filter(method -> "methodName".equals(method.getName())).
findFirst();
if (methodToFind.isPresent()) {
// invoke method or any logic needed
///methodToFind.get().
}
You can use Reflection in Java http://docs.oracle.com/javase/tutorial/reflect/index.html
or http://docs.oracle.com/javase/tutorial/reflect/member/methodType.html