Conundrum with package name in "dynamic" static factory method

Discussion in 'Java' started by Nobody, Jul 13, 2005.

  1. Nobody

    Nobody Guest

    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!
    Nobody, Jul 13, 2005
    #1
    1. Advertising

  2. "Nobody" <> wrote in message
    news:dVfBe.109793$...
    > 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!


    *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()
    Mike Schilling, Jul 14, 2005
    #2
    1. Advertising

  3. Nobody wrote:
    > 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.
    >


    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

    --
    XML is the programmer's duct tape.
    Raymond DeCampo, Jul 14, 2005
    #3
  4. Nobody

    Wibble Guest

    Raymond DeCampo wrote:
    > Nobody wrote:
    >
    >> 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.
    >>

    >
    > 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
    >


    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.
    Wibble, Jul 14, 2005
    #4
  5. Nobody

    Nobody Guest

    Wibble wrote:
    > Raymond DeCampo wrote:

    [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.
    Nobody, Jul 14, 2005
    #5
  6. Nobody

    Nobody Guest

    Raymond DeCampo wrote:
    [snippage]
    > try {
    > theProduct = (Product)
    > Class.forName(
    > /****** Here's the "magic" ***************/
    > ProductFactory.class.getPackage().getName()
    > + '.' + requestedPF + "Product")
    > .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.
    Nobody, Jul 14, 2005
    #6
  7. Nobody

    Hemal Pandya Guest

    Nobody wrote:
    > Wibble wrote:
    > > Raymond DeCampo wrote:

    > [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.
    Hemal Pandya, Jul 14, 2005
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. javaguy44
    Replies:
    6
    Views:
    10,697
    javaguy44
    Sep 22, 2004
  2. Matthias Kaeppler
    Replies:
    22
    Views:
    921
    Thomas G. Marshall
    May 24, 2005
  3. Medi Montaseri
    Replies:
    17
    Views:
    826
    Medi Montaseri
    Sep 3, 2003
  4. C#
    Replies:
    4
    Views:
    381
  5. Chris
    Replies:
    7
    Views:
    131
    sisyphus
    Nov 18, 2010
Loading...

Share This Page