Solved

Forcing object creation through a factory

Posted on 2006-10-30
29
562 Views
Last Modified: 2008-02-01
In Java, how does one force someone to call a factory in order to create an object of some type (i.e. MyFactory.createObjectA()) and have it so they cannot create an instance of that object without the factory?
0
Comment
Question by:DiamonDogX
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 8
  • 5
  • 5
  • +2
29 Comments
 
LVL 6

Accepted Solution

by:
valipotor earned 25 total points
ID: 17834131
You cannot force something like that.
Even if the constructor is private() the class can still be instantiated using introspection.

The coder must obey the rules of creating the object throgh a factory, in order for the app to be extended or patch without the need to recompile it.

0
 
LVL 20

Assisted Solution

by:Venabili
Venabili earned 25 total points
ID: 17834191
Or if you do not trust the developer - make your constructor to determine which is the calling class and initialise only if it is the factory
This was working in 1.4.2
http://www.aptana.com/dev/index.php/Determining_the_calling_method_in_Java
I think there was a better way in Java 5, but let me try to find it

However - I would simply not do it... :) The Developer is supposed to use the thing in the way specified by the API...
0
 
LVL 11

Expert Comment

by:dbkruger
ID: 17834426
If the constructor is private, then introspection will fail to acquire the method. You should be able to use that method to restrict who can call it.
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 20

Expert Comment

by:Venabili
ID: 17834441
If the constructor is private, how the Factory will call it? Because from what I read here, The Asker needs a second class to create objects from his class... :)
0
 
LVL 11

Expert Comment

by:dbkruger
ID: 17834457
public class TestIntrospect {
      public static void main(String args[]) {
            Class c = Foo.class;
            try {
                  Object x = c.newInstance();
            } catch (Exception e) {
                  System.out.println(e);
            }
      }

}
class Foo {
      private Foo() { System.out.println("Can't call me!"); }
}


java.lang.IllegalAccessException: Class TestIntrospect can not access a member of class Foo with modifiers "private"
0
 
LVL 20

Expert Comment

by:Venabili
ID: 17834468
Yep - the private constructor cannot be called from outside at all - this is for sure. But the Asker needs a Factory class to call it. :)
0
 
LVL 11

Expert Comment

by:dbkruger
ID: 17834475
> If the constructor is private, how the Factory will call it? Because from what I read here, The Asker needs a second class to create objects from his class... :)

In C++ you would use a friend. In Java, since that's not available, you use an inner class.

public class NotToBeInstantiatedByItself {
  private NotToBeInstantiatedByItself( ... ) { .. }


  public Factory gimmeAFactory() { ..}

  public static class FooFactory extends Factory {

  }
}
0
 
LVL 20

Expert Comment

by:Venabili
ID: 17834508
The problem is that the Asker do not ask for inner classes. :) He asks for 2 separate classes...
The inner classes are good solution. To some extent... But not the perfect one.

Basically Java do not have the friends concept - sometimes I really miss it. Yes - you can go very close but not really to make it the same...

Protected constructor for class A and Factory class in the same package is what I usually use in such cases. And good documentation explaining how to create objects of the class. Usually works.
0
 
LVL 6

Expert Comment

by:valipotor
ID: 17834690
To dbkruger & Venabili:

I wanted to say that a class can be instantiated even if the constructor was made private.

For example:


 Class a = A.class;
      try {
         Constructor contst = a.getDeclaredConstructor();
         contst.setAccessible(true);
         contst.newInstance();
      } catch (IllegalArgumentException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      } catch (InstantiationException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      } catch (IllegalAccessException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      } catch (InvocationTargetException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      } catch (SecurityException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      } catch (NoSuchMethodException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }

where class a is defined :

public class A {

   private A()
   {
      System.out.println("prevent instantiation");
   }
}
0
 
LVL 5

Expert Comment

by:kannan_ekanath
ID: 17834723
valipotor

Your argument is sorta wrong.
 contst.setAccessible(true);

consults the JVM security manager to check if private access of fields is allowed. However in typical production environment or for that matter in most app-servers, these flags are set to the level of security where private accesses of field will result in IllegalAccessException
0
 

Author Comment

by:DiamonDogX
ID: 17834800
So basically the closest solution is to put the factory and the object you want to instantiate via the factory (with a protected constructor) in the same package and then just call the factory method from anywhere... ?
0
 
LVL 20

Expert Comment

by:Venabili
ID: 17834822
Yep.
Or in the constructor of class A check who is the calling class and method and do something based on this. But I personally had never really done this :)
0
 
LVL 11

Expert Comment

by:dbkruger
ID: 17834918
I would put it in the class wth a private constructor, as my example showed. If you put it in the package, anyone can write a class in that package and you have allowed them access.

If you use protected, any child could get it as well. If we could all declare who our parents are, Donald Trump and Queen Elizabeth would probably have a lot of self-declared "children" hoping to inherit.
0
 
LVL 11

Expert Comment

by:dbkruger
ID: 17834937
Venabili --
You don't need to write the class as an inner class, you only need a tiny wrapper which instantiates the object in question and calls the generic factory.
But I think my post above highlights why you cannot sensibly use protected....
0
 
LVL 5

Expert Comment

by:kannan_ekanath
ID: 17834981
A factory is no different from any other java class. In fact you are hitting one of the design patterns called "Singleton Pattern"

http://www.fluffycat.com/Java-Design-Patterns/Factory-Method/

Let me suggest smething I found best. Integrate the Factory class into the same class; For example,

class SomeImportantObject {
     SomeImportantObject instance = new SomeImportantObject();

     private SomeImportantObject() {
        // no one other than this class can use it
     }

     public static SomeImportantObject getSingletonObject() {
          return instance;
     }
}
0
 
LVL 5

Expert Comment

by:kannan_ekanath
ID: 17835004
The above is something i found best, since most design experts would call "Singleton pattern" as somethign sort of "Anti pattern"

To put the argument in a different way, a singleton pattern if used badly beats the purpose of "Data encapsulation". If you have a class like above then it is equivalent to having a *DECLARED GLOBAL OBJECT* in C, C++ etc

Imagine, anyone can take that importantobject any time they want, call methods on it....

If your application needs it, then use it but use it sparingly :)
0
 

Author Comment

by:DiamonDogX
ID: 17835898
What seems to break encapsulation is reflection.  I am able to call private constructors and private methods of a class from outside of it!  It feels like hacking... I can call private methods in the java API classes through reflection as well.  Is there anything I'm missing?  Doesn't this type of thing seem vulnerable?
0
 
LVL 11

Expert Comment

by:dbkruger
ID: 17836335
I don't know how your permissions are set, but as I showed above, I could  not break encapsulation. If you have the code permissions set up properly, which they are by default, this should not happen. Reflection does not get you code that you could not otherwise access.
0
 

Author Comment

by:DiamonDogX
ID: 17836414
But I can set them to whatever I want... therefore, I can call the private methods...

Class c = MyClass.class;
Method m = c.getDeclaredMethods[ 0 ];
m.settAccessible( true );
m.invoke( null, null );
0
 
LVL 5

Expert Comment

by:kannan_ekanath
ID: 17840067
m.settAccessible( true );

This consults the security manager. Your security managers *allows* it. That was my previous comment :)

check the source code here,
http://docjar.com/docs/api/java/lang/reflect/AccessibleObject.html#setAccessible(boolean)

It consults reflect permission. Google it if you want to know how to turn it on/off
0
 

Author Comment

by:DiamonDogX
ID: 17842291
I understand that this concerns the security manager... my point is that I CAN turn this on or off and invoke private methods.  How does this work with the Java API classes?  I listed the methods for GridBagLayout.class for example and I saw a private method called removeConstraints() that I was able to invoke.  What else am I missing here?  Obviously the Java API classes are secure...
0
 
LVL 11

Expert Comment

by:dbkruger
ID: 17843273
Your code obviously cannot even compile, so I suggest you compile it before claiming it works.
A constructor is not a method
You have to have an object in order to invoke a method on it

Your code is below. I fixed it and tried to get the constructor, and was told it did not exist, the exception comes on the getConstructor method, so you don't even have the opportunity to try to set it.


>Class c = MyClass.class;
>Method m = c.getDeclaredMethods[ 0 ]; // WRONG
>m.settAccessible( true );
>m.invoke( null, null );

Correct (but fails on getConstructor)

import java.lang.reflect.*;


public class TestIntrospect {
      public static void main(String args[]) {
            Class c = Foo.class;
            try {
                  //Object x = c.newInstance();
                  Class[] parameterTypes = new Class[0];
                  Constructor con = c.getConstructor(parameterTypes);
                  con.setAccessible( true );
                  Object[] empty = new Object[0];
                  Object f = con.newInstance(empty);

            } catch (Exception e) {
                  System.out.println(e);
            }
      }

}
class Foo {
      private Foo() { System.out.println("Can't call me!"); }
}
0
 
LVL 6

Expert Comment

by:valipotor
ID: 17844498
As I have already posted:

Class a = A.class;
      try {
         Constructor contst = a.getDeclaredConstructor();
         contst.setAccessible(true);
         contst.newInstance();
      } catch (Throwable e) {
         e.printStackTrace();
      }

where class a is defined :

public class A {

   private A()
   {
      System.out.println("Can't call me? ");
   }
}
0
 

Author Comment

by:DiamonDogX
ID: 17844530
I was just about to post the exact same thing valipotor :).  It definitely compiles, and definitely prints out "Can't call me? "
0
 
LVL 6

Expert Comment

by:valipotor
ID: 17844542
Yes, it is a matter of security manager.

As kannan_ekanath said:

>> This consults the security manager. Your security managers *allows* it.
0
 
LVL 11

Expert Comment

by:dbkruger
ID: 17845004
Sorry, copied the wrong code of yours. The other one doesn't compile. My environment does stop you from doing this.
0

Featured Post

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Oracle SQL syntax check  without executing 6 107
Fast way to search item into Java Array (Rhino compatible) 2 39
spring maven example issues 3 43
Java List 4 41
Java functions are among the best things for programmers to work with as Java sites can be very easy to read and prepare. Java especially simplifies many processes in the coding industry as it helps integrate many forms of technology and different d…
In this post we will learn how to connect and configure Android Device (Smartphone etc.) with Android Studio. After that we will run a simple Hello World Program.
Viewers learn about the third conditional statement “else if” and use it in an example program. Then additional information about conditional statements is provided, covering the topic thoroughly. Viewers learn about the third conditional statement …
The viewer will learn how to implement Singleton Design Pattern in Java.

733 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question