A
alan
A major annoyance for me is that the reflection errors do not
have a common root. What was the logic behind that?
have a common root. What was the logic behind that?
A major annoyance for me is that the reflection errors do not
have a common root. What was the logic behind that?
Can you say about what errors you are talking about ?
Aren't they all extending the class Error ?
Which means that function signatures look like this.
void doSomeReflection() throws IllegalAccessExcpetion,
InvocationTargetException, IllegalAccessExcpetion,
NoSuchMethodException, SecurityException;
Just:
public Object invoke(Object obj, Object[] args)
throws
IllegalAccessException,
IllegalArgumentException,
InvocationTargetException
will cover it. Indeed the above is cut-n-pasted from the JavaDoc.
Three separate "kinds" of exception is, um, exceptional, but it's not
clear
that they /should/ share any natural superclass.
OTOH, since the method invoked by reflection may throw /anything/ I don't
see
much point (except the documentary value) in declaring Method.invoke() to
throw
anything more specific than Throwable.
Anything the invoked method throws is wrapped by
They're all extending Exception, most RuntimeException.
The problem is that Method.invoke throws:
- Object
+- Throwable
+- Exception
+- IllegalAccessException
+- InvocationTargetException
+- RuntimeException
+- IllegalArgumentException
Which means that function signatures look like this.
void doSomeReflection() throws IllegalAccessExcpetion,
InvocationTargetException, IllegalAccessExcpetion,
NoSuchMethodException, SecurityException;
Or else like this.
void doSomeReflection() throws Exception;
That that last one is a no-no.
What was the logic behind that?
Which means that function signatures look like this.
void doSomeReflection() throws IllegalAccessExcpetion,
InvocationTargetException, IllegalAccessExcpetion,
NoSuchMethodException, SecurityException;
Just:
public Object invoke(Object obj, Object[] args)
throws
IllegalAccessException,
IllegalArgumentException,
InvocationTargetException
will cover it. Indeed the above is cut-n-pasted from the JavaDoc.
Three separate "kinds" of exception is, um, exceptional, but it's not clear
that they /should/ share any natural superclass.
OTOH, since the method invoked by reflection may throw /anything/ I don't
see much point (except the documentary value) in declaring Method.invoke()
to throw anything more specific than Throwable.
I think the OP intends doSomeReflection() to find the method as well as
invoke it, though in that case I'd probably catch NoSuchMethodException and
SecurityException within doSomeReflection and rethrow some exception that
means "no accessible method found".
Just:
public Object invoke(Object obj, Object[] args)
throws
IllegalAccessException,
IllegalArgumentException,
InvocationTargetException
will cover it. Indeed the above is cut-n-pasted from the JavaDoc.
Three separate "kinds" of exception is, um, exceptional, but it's not
clear
that they /should/ share any natural superclass.
OTOH, since the method invoked by reflection may throw /anything/ I don't
see
much point (except the documentary value) in declaring Method.invoke() to
throw
anything more specific than Throwable.
Anything the invoked method throws is wrapped by InvocationTargetException.
The defined exceptions do IMHO a reasonable job of separating out the things
that can go wrong:
IllegalAccessException
you're not allowed to call this method
IllegalArgumentException
you can call this method, but not with the supplied arguments
InvocationTargetException
you called the method just fine, but it threw an exception
Or like this:
void doSomeReflection() throws OopsInMyReflectionException;
In other words, if you want to present a simpler API then you can
catch all the various exceptions internally and wrap each in an
instance of some for-purpose custom exception.
To make you think twice before using reflection?
IMO, reflective method invocation is almost always a sign of poor
application design. Except in a few very specialized cases, if you have
enough information about an object to sensibly invoke methods on it via
reflection, then you have enough information to construct a means to
invoke them normally. This may involve defining an interface that the
object's class must implement, and assigning the object reference to a
variable of the interface type. There are sometimes other alternatives.
[Me:][Alan:]Or like this:
void doSomeReflection() throws OopsInMyReflectionException;
In other words, if you want to present a simpler API then you can
catch all the various exceptions internally and wrap each in an
instance of some for-purpose custom exception.
Righto. Was concerned about getting into the perpetually wrapped
exception with that. (Not being contrarian. Stating my concern.)
Um, okay, a valid design reason is to say, we think you should
design your own exception heirarchy, we can't anticiplate your
needs, but we've atomized it for you. If you use it once or
twice in your program, here's what you need to worry about. If
you're writing a reflective application, then think of an
exception handling strategy approprite for your application.
That to me is a more professional sentiment than discouraging
use. I'd hate to think the API was nagging me, punishing me for
my design decisions.
I suppose then, I should proceed to develop a reflection API as
I like it.
IMO, reflective method invocation is useful for cofiguration and
for testing. Two places where speed is not an issue, but
flexibilty is. Two very common appliations.
JUnit, Ant, XStream, JavaBeans, BeanShell, OGNL, Jetty, etc.
Plenty of quality projects use reflection appropriately.
It covered Method.invoke, but not the calls to Class.getMethod
which go hand in hand. Yes. The three cover invoke. However, if
you have reflection as part of your package/library, and you are
not going to handle reflection exceptions yourself, your
signatures start to look like the above.
Agreed?
Yes.
But I'm not convinced of the value in allowing the exceptions to escape "raw".
The point of wrapping the java.lang.reflect.* stuff up in your own
library is presumably to make it less inconvenient to use, so
/forcing/ client code to distinguish between the various reasons a
reflective invocation can fail seems counterproductive to me. I'd
wrap the raw exception (non-)hierarchy up in my own little
hierarchy (and I'd probably extend the API of the exceptions I
used to include (IMO) proper OO methods like isProgrammingError()
(some potential exceptions are, some aren't, and I don't think
that client code should be forced to switch-on-class to tell which
is which).
(e-mail address removed) wrote:
[Alan:][Me:]Which means that function signatures look like this.[Alan:]Or like this:
void doSomeReflection() throws OopsInMyReflectionException;
In other words, if you want to present a simpler API then you can
catch all the various exceptions internally and wrap each in an
instance of some for-purpose custom exception.
Righto. Was concerned about getting into the perpetually wrapped
exception with that. (Not being contrarian. Stating my concern.)
If you don't want to wrap then discard the original exception instead.
I don't see how it's useful to gratuitously dump potentially valuable
data, but you can do it if it better suits your sensibilities.Um, okay, a valid design reason is to say, we think you should
design your own exception heirarchy, we can't anticiplate your
needs, but we've atomized it for you. If you use it once or
twice in your program, here's what you need to worry about. If
you're writing a reflective application, then think of an
exception handling strategy approprite for your application.
I was being a bit flippant, sorry. Reflection seems to hold an
unhealthy fascination for some people, so I and some others here tend to
discourage its use. Wherever you can avoid or minimize your use of
reflection you are better off. As for the exceptions thrown by
Method.invoke(), there are two general cases:
[snip]
By breaking down the situation this way, the Reflection API gives
you the opportunity to handle each distinct situation in a manner
appropriate for your application. You only need explicit handling
for the two checked exceptions: IllegalAccessException and
InvocationTargetException. You would need at least the latter, or
something like it, in any generic reflection-type API.
The API is not nagging you: it is simply exhibiting its own
nature.
Agreed.
What's wrong with the API you already have?
That last part is another thing that has been a cause for
consideration for me lately. What good is exception handling if
you do not provide the information necessary to fix the
exception? Why FileNotFoundException cannot have a getFile() method?
(e-mail address removed) wrote:
Testing, yes. JUnit is one of the examples I was thinking of. Do
note, however, that even in JUnit reflection is only used behind
the scenes to provide convenience features to the test writer.
...application frameworks...
It is rarely necessary to design a regular application this way.
Both of those are commonly _used_ types of applications, but they
are not commonly _written_ types of applications. I stand on my
position (clarified) that it is rare to need to use reflective
method invocation in an application, that doing so is vastly
inferior to using normal method invocation when that is possible,
and that therefore reflective method invocation is almost always a
sign of poor application design or implementation.
Do note that it is possible to reflectively instantiate classes but
invoke methods on them normally. This is what a well-designed plug-in
type API will do; I believe Ant's custom tasks are an example, and JDBC
drivers certainly are. This is the sort of use that I generally think
of in support of custom application configuration, and is not covered by
my arguments against reflective method invocation.
Basically, if you need it then you're doing something wrong. If you do
intend to recover from a file that's not found, then the try/catch block
that catches FileNotFoundException should be limited enough that only
one File is opened within that block. That's the one that wasn't found.
If, on the other hand, you write exception handling for large sections
of code that open several files, then you're going to have a really
tough time recovering and trying again to open the file that failed.
Essentially, the answer is to write smaller try blocks.
public void fooHandler implements org.xml.sax.ContentHandler {
public void startElement(String ns, String ln, String qn, Attributes as)
throws SAXException {
FileInputStream in = null;
do {
try {
String fileName = as.getValue("foo-file");
in = new FileInputStream(new File(fileName));
} catch (FileNotFoundException e) (
errorHandler.fatalError(new SAXParseException(e));
}
} while (in == null);
}
}
The errorHandler can raise the SAXParseException. The errorHandler could
copy a dummy file into the position and continue processing, but it needs
the file name to do so.
If FileNotFoundException had a getFile() method, this would work, but
alas, it doesn't, an it don't.
This is a shortcoming of exceptions in general.
There are times when
smaller try blocks won't work, because the exception handling logic and
the point of failure are separated by a messaging conduit (like
reflection), and might not even share a call stack.
You're acting quite helpless about the whole thing, when you've clearly
just caught and rethrown an exception. You could rethrow any exception
you so desire. Why not wrap it in an exception that knows what file is
missing? That's a reasonable piece of information for a SAXException to
have, but superfluous for a FileNotFoundException, which is thrown in
response to an attempt to open a specific file. You are wrapping the
exception (exactly as you should), and you should include the additional
information when wrapping it.
It's quite explicitly not a shortcoming of exceptions in general. It is
quite possible to define an exception containing any information you
want it to contain. If you want an exception with additional
information, then define one and put the information there.
Nope. As long as you stick to the abstraction, smaller try blocks will
always be suitable.
In that case, it is not an abstraction, it is merely a language
construct. A block is a block, true, can't argue with that.
Want to reply to this thread or ask your own question?
You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.