Comments intermixed.

On Mon, 30 Sep 2002, John Bindel wrote:

> Date: Mon, 30 Sep 2002 13:49:22 -0500
> From: John Bindel <[EMAIL PROTECTED]>
> Reply-To: Struts Users Mailing List <[EMAIL PROTECTED]>
> To: Struts Users Mailing List <[EMAIL PROTECTED]>
> Subject: Re: [OT - Java] How can I do this in Java?
>
> On Mon, Sep 30, 2002 at 12:02:41PM -0500, Jerry Jalenak wrote:
>
> > Yeah, already ran across the exceptions. Right now I'm trying
> > to decide how to handle them since all of this code is actually
> > in a custom Validator routine.....
>
> Good Lord, people, why is reflection anything but the option of
> last resort here?
>

While I agree with you that using reflection was a poor design choice for
the problem stated here (the patterns should really be loaded from a data
file instead of introspecting from the class), your condemnation of
reflection in general is based on an incorrect definition of the term, and
also outdated behavior related to performance.  See below for more.

> You really do not want to be calling Class.forname(String) unless
> there is some class that cannot be loaded by the compiler. First,
> calling Class.forname is slow, and second, it perversely gets
> rid of the compile-time type-safety that you would have is you
> simply used MyClass.class.
>

The Class.forName() method is not really reflection -- it is dynamic class
loading.  Struts itself uses this to good effect, because it's not
possible to know (at the time ActionServlet is compiled) the names of all
the Action and ActionForm subclasses that *your* application will be
using.

Further, there is no loss of type safety when using dynamic class loading
in the usual fashion, because you normally cast to the base class you are
looking for.  For example, module error checking, this is how Struts
actually loads an Action class instance:

  ClassLoader loader =
    Thread.currentThread().getContextClassLoader();
  if (classLoader == null) {
    loader = this.getClass().getClassLoader();
  }
  Action action = (Action) loader.loadClass(actionClassName);

Note the cast to an Action, which protects you from type safety problems.

Of course, using dynamic class loading in the use case being discussed in
this mail thread was totally unnecesary.  But please stop casting
aspersions on a very useful feature of the Java language that makes
dynamically extensible applications like Struts possible in the first
place.

> Reflection is a tool that's useful when you do not know at build
> time the classes with which you will be dealing. It's useful for
> discovery of APIs. Using reflection instead of a lookup table
> is needlessly obtuse and will cause your VM to do all sorts of
> work on which any programmer should not want to be wasting CPU
> cycles.
>
>
> 1. Using reflection here is fragile, especially if it's not wrapped
> within the class that defines your constants. Java is a strongly
> typed language so letting the compiler help you is encouraged.
>

Since the problem at hand was to access *data*, the best approach would be
to store the patterns externally in a properties file.  Then, the data
could be used by multiple classes when it is needed (including the class
in which the format strings are currently embedded).

> 2. Using reflection is slow. If you still think it's the way you
> want to go, I would strongly recommend limiting the times you
> call Class.forname, etc., such that you do not call it every time
> you validate the zip code.
>

Firstly, as above, Class.forName() is not reflection.

Secondly, a subsequent call to Class.forName() for the same class name is
*not* going to load the class bytecodes again; the class loader will
remember that the requested class name has already been loaded, and just
returns you the same instance.

Thirdly, there is *zero* performance difference (at runtime) between
loading a class via Class.forName() and loading one (for the first time)
with a "new" operator.  Why?  Because they both end up calling the exact
same loadClass() method -- it's just a question of whether the developer
calls the method explicitly or the bytecodes generated by the compiler
call it for you.

As for the performance of real life uses of reflection, have you ever
noticed how Struts actually implements the population of your form bean
properties from the request parameters?  Yep ... that's right ... every
single call to a property setter is done via reflection.  Seems fast
enough to me, especially on a 1.4 JDK where the performance difference
between direct calls and reflected calls is very very small.

> 3. Using reflection makes you check all sorts of exceptions for
> things that you as the programmer know should not occur, but only
> can be you are circumventing the type checking provided by the
> language.  This is a clue that what should be a simple task is
> being made more complex than it needs to be.
>

In the particular use case at hand, reflection is the wrong technology to
use.  However, it makes possible some things that would otherwise be
impossible, or insanely complicated (to do form bean population without
using reflection, Struts would have to examine all your form beans, then
generate a custom Java class to do the auto-population and make sure these
classes were all compiled and included in your webapp -- not something
that can be guaranteed in a portable fashion).

> 4. I'm not sure what your application is, but using regexp strings
> to validate ZIP codes per state seems like a bad idea. The US
> post office makes new ZIP codes all the time, and unless you are
> getting a list from them every week, the most you may want your
> application to do is warn the user that the application doesn't
> recognize the ZIP code.
>

It doesn't look like he wanted to check the exact codes, just that the
code is in the correct range for that state.  This is a perfectly
reasonable compromise if you cannot afford the time to do the database
lookup, or you don't have the mechanisms to maintain a current list of all
the individual codes in your database.

> 5. Tell your product managers that validating ZIP codes is not
> something you can do reliably without an often-updated list of
> ZIP codes that you would need to download from the Post Office
> on a regular schedule since your list of regexp string will
> become outdated.
>
> 6. Lookup tables implemented by arrays or HashMaps are orders
> of magnitude faster than the sequence of function calls and system
> calls that you have to do with reflection.
>
>
> I'm sorry I had to write this, but I am befuddled by the lack
> of outcry over using reflection instead of a simple lookup table.
>

I'm saddened by the fact that you take a case of misuese of a particular
feature and turn it into a diatribe against ever using it.

> Cheers,
> John

Craig


>
> > > -----Original Message-----
> > > From: Taylor, Jason [mailto:[EMAIL PROTECTED]]
> > > Sent: Monday, September 30, 2002 11:57 AM
> > > To: 'Struts Users Mailing List'
> > > Subject: RE: [OT - Java] How can I do this in Java?
> > >
> > >
> > > good point-- you'd also want to printStackTrace() (if possible) before
> > > rethrowing InvocationTargetException, since it can be
> > > difficult to debug an
> > > ITE otherwise...
> > >
> > > -----Original Message-----
> > > From: Daniel Jaffa [mailto:[EMAIL PROTECTED]]
> > > Sent: Monday, September 30, 2002 9:49 AM
> > > To: Struts Users Mailing List
> > > Subject: Re: [OT - Java] How can I do this in Java?
> > >
> > >
> > > Make sure your code in a  proper try and catch.  Using
> > > reflection spits out
> > > nasty errors if  anything is not right.:(
> > >
> > > ClassCastException
> > > IllegalAccessException
> > > NoSuchMethodException
> > > InvocationTargetException
> > >
> > > Daniel jaffa
> > > ----- Original Message -----
> > > From: "Jerry Jalenak" <[EMAIL PROTECTED]>
> > > To: "'Struts Users Mailing List'" <[EMAIL PROTECTED]>
> > > Sent: Monday, September 30, 2002 11:46 AM
> > > Subject: RE: [OT - Java] How can I do this in Java?
> > >
> > >
> > > > Jason - Thanks for the code snippet - worked like a charm
> > > first time!  I
> > > > tend to get lost in JavaDoc sometimes, so this was a nice
> > > example to have
> > > on
> > > > how to wind my way through to the answer!  Thanks again!
> > > >
> > > > John - Thanks for the suggestion on using the HashMap.  I'm
> > > going to file
> > > it
> > > > away for now and use Jason's reflection method - but it
> > > never hurts to
> > > have
> > > > a couple of different methods to use on something like this!
> > > >
> > > > Thanks guys!
> > > >
> > > > Jerry
> > > >
> > > > > -----Original Message-----
> > > > > From: Taylor, Jason [mailto:[EMAIL PROTECTED]]
> > > > > Sent: Monday, September 30, 2002 10:28 AM
> > > > > To: 'Struts Users Mailing List'
> > > > > Subject: RE: [OT - Java] How can I do this in Java?
> > > > >
> > > > >
> > > > > I don't happen to have any sample code that does exactly what
> > > > > you're doing,
> > > > > but off the top of my head (with a little help from sun's
> > > > > javadoc) I'd say
> > > > > it's something like:
> > > > >
> > > > > import java.lang.reflect.Field;
> > > > >
> > > > > String stateCode = "AK";
> > > > > Class constantClass =
> > > > > Class.forName("com.yourdomain.yourapp.Constants");
> > > > > Field stateField = constantClass.getDeclaredField(stateCode);
> > > > > String stateRegExp = (String) stateField.get(constantClass);
> > > > > System.err.println("regexp for "+stateCode+": "+stateRegExp);
> > > > >
> > > > > I don't really know any more about reflection than you, I
> > > > > just followed the
> > > > > trail from java.lang.Class to java.lang.reflect.Field.  Once
> > > > > you've done it
> > > > > once, you see it's no mystery-- you're just doing runtime
> > > compiling.
> > > > >
> > > > > HTH-- This is just how I'd start, as I haven't tested or used
> > > > > this code.  If
> > > > > I'm wrong, I'm sure you can figure out what I missed by
> > > > > studying the API
> > > > > docs.  If, on the other hand, you don't like reading javadocs
> > > > > and generating
> > > > > your own test cases, LOL!
> > > > >
> > > > > -JT
> > > > >
> > > > > -----Original Message-----
> > > > > From: Jerry Jalenak [mailto:[EMAIL PROTECTED]]
> > > > > Sent: Monday, September 30, 2002 8:05 AM
> > > > > To: 'Struts Users Mailing List'
> > > > > Subject: RE: [OT - Java] How can I do this in Java?
> > > > >
> > > > >
> > > > > Jason,
> > > > >
> > > > > Thanks for the quick reply.  I just took at look at the
> > > > > API's, but don't yet
> > > > > understand enough about reflection to know how to
> > > implement it.  Just
> > > > > looking at the methods I don't see a way to do what I want -
> > > > > any chance that
> > > > > you'd have some sample code laying about?
> > > > >
> > > > > Jerry
> > > > >
> > > > > > -----Original Message-----
> > > > > > From: Taylor, Jason [mailto:[EMAIL PROTECTED]]
> > > > > > Sent: Monday, September 30, 2002 9:59 AM
> > > > > > To: 'Struts Users Mailing List'
> > > > > > Subject: RE: [OT - Java] How can I do this in Java?
> > > > > >
> > > > > >
> > > > > > sounds like a job for reflection (java.lang.reflect.*;) Have
> > > > > > you looked at
> > > > > > java.lang.Class and java.lang.reflect.Field?
> > > > > >
> > > > > > -----Original Message-----
> > > > > > From: Jerry Jalenak [mailto:[EMAIL PROTECTED]]
> > > > > > Sent: Monday, September 30, 2002 7:50 AM
> > > > > > To: '[EMAIL PROTECTED]'
> > > > > > Subject: [OT - Java] How can I do this in Java?
> > > > > >
> > > > > >
> > > > > > OK - off topic, but Sun's java forum sucks, and there are an
> > > > > > incredible
> > > > > > number of Java guru's on this list, so I thought I'd throw
> > > > > > this out here.
> > > > > > (That and I am using this in a custom validation routine
> > > > > > :-))    Any help
> > > > > > would be GREATLY appreciated!
> > > > > >
> > > > > > Here's the scenario - I've got a series of static constants
> > > > > > that represent
> > > > > > Java regular expressions.  These RE's are used to validate
> > > > > > driver license
> > > > > > formats for the 50 states + DC.  The strings look like this:
> > > > > >
> > > > > > public static final String AK = "^[0-9]{1,7}$";
> > > > > > public static final String AL = "^[0-9]{7}$";
> > > > > > public static final String AR = "^[0-9]{8,9}$";
> > > > > > public static final String AZ =
> > > > > > "^[0-9ABDY][0-9]{8}$|^[A-Z][0-9]{3,6}$|^[A-Z]{2}[0-9]{3,5}$";
> > > > > > public static final String CA = "^[A-Z][0-9]{4,7}$";
> > > > > > public static final String CO =
> > > > > > "^[A-Z][0-9]{1,6}$|^[A-Z]{2}[0-9]{1,6}$|^[0-9]{9}$";
> > > > > > etc. etc. etc.
> > > > > >
> > > > > > On my form I have a drop-down box of states, and a field for
> > > > > > the license
> > > > > > number.  In my custom validator routine, I pick up the value
> > > > > > of the state,
> > > > > > and build a string to represent the constant - i.e.
> > > > > >
> > > > > > private static boolean validateDriversLicenseNumber(String
> > > > > > licenseState, String licenseNumber)
> > > > > > {
> > > > > > String licenseConstant = "Constants." + licenseState;
> > > > > >
> > > > > > I then want to use "licenseConstant" in a Pattern / Match:
> > > > > >
> > > > > > Pattern p = Pattern.compile(licenseConstant,
> > > > > > Pattern.CASE_INSENSITIVE);
> > > > > > Match m = p.matcher(licenseNumber);
> > > > > > return (m.find());
> > > > > > }
> > > > > >
> > > > > > Obviously the line "String licenseConstant = "Constants." +
> > > > > > licenseState;"
> > > > > > does not give me the value of Constant.<state name>; the
> > > > > > question I have is,
> > > > > > is there a method (or something) that will allow me to build
> > > > > > such a string,
> > > > > > and return the value (i.e. the regular expression)?  Or is
> > > > > > there a better
> > > > > > way of doing this?
> > > > > >
> > > > > > TIA!
> > > > > >
> > > > > > Jerry Jalenak
> > > > > > Web Publishing
> > > > > > LabOne, Inc.
> > > > > > 10101 Renner Blvd.
> > > > > > Lenexa, KS  66219
> > > > > > (913) 577-1496
> > > > > > [EMAIL PROTECTED]
> > > > > >
> > > > > >
> > > > > > This transmission (and any information attached to it) may be
> > > > > > confidential
> > > > > > and is intended solely for the use of the individual or
> > > > > > entity to which it
> > > > > > is addressed. If you are not the intended recipient or
> > > the person
> > > > > > responsible for delivering the transmission to the intended
> > > > > > recipient, be
> > > > > > advised that you have received this transmission in error and
> > > > > > that any use,
> > > > > > dissemination, forwarding, printing, or copying of this
> > > > > information is
> > > > > > strictly prohibited. If you have received this transmission
> > > > > > in error, please
> > > > > > immediately notify LabOne at (800)388-4675.
> > > > > >
> > > > > >
> > > > > >
> > > > > > --
> > > > > > To unsubscribe, e-mail:
> > > > > > <mailto:[EMAIL PROTECTED]>
> > > > > > For additional commands, e-mail:
> > > > > > <mailto:[EMAIL PROTECTED]>
> > > > > >
> > > > >
> > > > > This transmission (and any information attached to it) may be
> > > > > confidential
> > > > > and is intended solely for the use of the individual or
> > > > > entity to which it
> > > > > is addressed. If you are not the intended recipient or the person
> > > > > responsible for delivering the transmission to the intended
> > > > > recipient, be
> > > > > advised that you have received this transmission in error and
> > > > > that any use,
> > > > > dissemination, forwarding, printing, or copying of this
> > > information is
> > > > > strictly prohibited. If you have received this transmission
> > > > > in error, please
> > > > > immediately notify LabOne at (800)388-4675.
> > > > >
> > > > >
> > > > >
> > > > > --
> > > > > To unsubscribe, e-mail:
> > > > > <mailto:[EMAIL PROTECTED]>
> > > > > For additional commands, e-mail:
> > > > > <mailto:[EMAIL PROTECTED]>
> > > > >
> > > >
> > > > This transmission (and any information attached to it) may
> > > be confidential
> > > and is intended solely for the use of the individual or
> > > entity to which it
> > > is addressed. If you are not the intended recipient or the person
> > > responsible for delivering the transmission to the intended
> > > recipient, be
> > > advised that you have received this transmission in error and
> > > that any use,
> > > dissemination, forwarding, printing, or copying of this information is
> > > strictly prohibited. If you have received this transmission
> > > in error, please
> > > immediately notify LabOne at (800)388-4675.
> > > >
> > > >
> > > >
> > > > --
> > > > To unsubscribe, e-mail:
> > > <mailto:[EMAIL PROTECTED]>
> > > > For additional commands, e-mail:
> > > <mailto:[EMAIL PROTECTED]>
> > > >
> > >
> > >
> > > --
> > > To unsubscribe, e-mail:
> > > <mailto:[EMAIL PROTECTED]>
> > > For additional commands, e-mail:
> > > <mailto:[EMAIL PROTECTED]>
> > >
> >
> > This transmission (and any information attached to it) may be confidential and is 
>intended solely for the use of the individual or entity to which it is addressed. If 
>you are not the intended recipient or the person responsible for delivering the 
>transmission to the intended recipient, be advised that you have received this 
>transmission in error and that any use, dissemination, forwarding, printing, or 
>copying of this information is strictly prohibited. If you have received this 
>transmission in error, please immediately notify LabOne at (800)388-4675.
> >
> >
> >
> > --
> > To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
> > For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>
>
> --
> end of line
>
>
> --
> To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>
>
>


--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to