Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / July 2005

Tip: Looking for answers? Try searching our database.

Conundrum with package name in "dynamic" static factory method

Thread view: 
Nobody - 13 Jul 2005 22:42 GMT
Hi,

In the spirit of "most maintainable" code, I'm applying a factory method
to instantiate objects using part of a class name that's passed to the
factory method, followed by reflection and newInstance(). The code goes
something like this:

public static Product loadProductDynamically(String requestedPF)
    throws UnsupportedProductFactoryException
{
    Product theProduct;
    try {
        theProduct=
            (Product) Class.forName(requestedPF + "Product").
            newInstance();
    } catch (InstantiationException e) {
        throw new UnsupportedProductFactoryException();
    } catch (IllegalAccessException e) {
        throw new UnsupportedProductFactoryException();
    } catch (ClassNotFoundException e) {
        throw new UnsupportedProductFactoryException();
    }
    return theProduct;
}

This works great if everything (this class, the *Product classes) is in
the "default" package. As soon as I put the code in another named
package, the forName() method above doesn't work. Obviously you have to
specify the package part of the class.

But, how can I get the package name in a static method like the one
above without hard-coding the package name anywhere in the class?
Ideally, this kind of code should work for any class in any package,
e.g., expecting that the "*Product" classes are in the same package.

Thanks in advance!
Mike Schilling - 14 Jul 2005 01:23 GMT
> Hi,
>
[quoted text clipped - 32 lines]
>
> Thanks in advance!

*Someone* needs to know the package name.  You can hardcode it in the
factory or have the caller pass it in.  If you want to the class to be in
the same package as some other object, then change your signature to:

   public static Product loadProductDynamically(String requestedPF, Object
inSamePackage)

and calculate the package name from

   inSamePackage.getClass().toString()
Raymond DeCampo - 14 Jul 2005 01:39 GMT
> Hi,
>
[quoted text clipped - 30 lines]
> Ideally, this kind of code should work for any class in any package,
> e.g., expecting that the "*Product" classes are in the same package.

Assume that your code above lives in the class ProductFactory.  I also
assume your Product implementations live in the same package.  Then you
can use the following (untested, uncompiled):

public class ProductFactory
{
    public static Product loadProductDynamically(String requestedPF)
        throws UnsupportedProductFactoryException
    {
        Product theProduct;
        try {
            theProduct = (Product)
                Class.forName(
                    /****** Here's the "magic" ***************/
                    ProductFactory.class.getPackage().getName()
                    + '.' + requestedPF + "Product")
                    .newInstance();
        } catch (InstantiationException e) {
            throw new UnsupportedProductFactoryException();
        } catch (IllegalAccessException e) {
            throw new UnsupportedProductFactoryException();
        } catch (ClassNotFoundException e) {
            throw new UnsupportedProductFactoryException();
        }
        return theProduct;
    }
}

Of course, this won't work in the default package, but I assume those
days are behind you.

HTH,
Ray

Signature

XML is the programmer's duct tape.

Wibble - 14 Jul 2005 03:06 GMT
>> Hi,
>>
[quoted text clipped - 64 lines]
> HTH,
> Ray

I forgot...  Why is this ugly reflective mess that drops exception
details and instantiates arbitrary classes "most maintainable"?  Smells
kinda bad to me.  I hope theres a good reason for this thing.
Nobody - 14 Jul 2005 12:05 GMT
[snip of java code]
> I forgot...  Why is this ugly reflective mess that drops exception
> details and instantiates arbitrary classes "most maintainable"?  Smells
> kinda bad to me.  I hope theres a good reason for this thing.

Have you ever done a factory method before without reflection? It's a
big, uglier "if" statement with hard-coded class names - smells like
hard-coded methods crying for polymorphism. If that approach is more
maintainable, I don't see how, but I'm willing to listen to your
explanation.

Although a big if statement with "new" statements may be more readable,
adding support for a new sub-class is harder to maintain, because you
have to add the new if/then statement with the instantiation. If your
saying ultimately that the factory method design pattern is what's
harder to maintain, then maybe that's because design patterns are always
less obvious to those who've never seen them. The beauty of the approach
proposed here is that you simply create the new XyzProduct class and
drop it into the package. No code in the factory has to be changed.
There are arguments that this is risky in terms of security (which I
suppose was the meaning of your "arbitrary classes" comment).

The exceptions would exist in either factory implementation
(with/without reflection), but the example has simplified them. BTW,
this example was shown in Bruce Eckel's book, Thinking in Java, if I
recall correctly.
Hemal  Pandya - 14 Jul 2005 17:50 GMT
> [snip of java code]
> > I forgot...  Why is this ugly reflective mess that drops exception
> > details and instantiates arbitrary classes "most maintainable"?  Smells
> > kinda bad to me.  I hope theres a good reason for this thing.
>
> Have you ever done a factory method before without reflection?

I have. Almost always, when the range of classes that can be
instantiated by the factory is known at compile time.

> It's a
> big, uglier "if" statement with hard-coded class names -

My code has a lot many other hard-coded class names. Most of my
variables are of hard-coded types actually. And I respectfully suspect
so are yours. <grin>

> If that approach is more
> maintainable, I don't see how, but I'm willing to listen to your
> explanation.

It maybe slightly less maintainable, because as you point out the
factory method has to be modified every time a candidate class is added
to the code base. But  I am willing to tolerate the incremental effort
over creating that candidate class itself.

> Although a big if statement with "new" statements may be more readable,

Besides readability, it provides compile-time type checking and
declares in-code the range of classes that can be instantiated  by the
factory.
Nobody - 14 Jul 2005 15:34 GMT
[snippage]
>         try {
>             theProduct = (Product)
[quoted text clipped - 4 lines]
>                     .newInstance();
>         } catch (InstantiationException e) {
[snippage]

Thanks! That did the trick!

I feel a bit silly - but I forgot about the "class" literal in Java
(http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#251530)
- It's interesting that Eclipse's Java editor treats ".class" as a
static attribute of the ProductFactory (or any class for that matter),
while it suggests possibilities to complete the text "ProductFactory."
(dot completion).

I actually started trying to find a solution before posting on usenet,
and I looked for such a static attribute in the Object class - that
seems like a logical and intuitive place for it. However, this is a
feature of the language, not Object.

Anyway, the code done the way you propose above should even tolerate a
refactoring rename of the class ProductFactory without breaking, thus
respecting my criterion or it being non hard-coded. As I understand
.class, the above "magic" could have been written
Class.forName("ProductFactory").getPackage().getName() - but this would
likely not get cleanly refactored in a class displacement/rename as the
class name is in a string literal.


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.