View Full Version : How to specify/make a bean as immutable in beanfactory
sjeelani
Aug 17th, 2004, 03:53 PM
Hi,
I am to newbie to spring, hence pardon for any dumb questions.
I was going thru beanfactory xml and spring has a support for specifying whether a bean is singleton or prototype. I would like to know whether there is way I can say that particular bean is immutable (ex: <bean name="yetAnotherExample" class="examples.ExampleBeanTwo" immutable="true"/>and when I declare it as immutable, spring automatically uses '==' for equality (obj1 == obj2) rather than equals().
Thanks,
Jeelani
Colin Sampaleanu
Aug 17th, 2004, 04:32 PM
There's no immutable flag, but I'm confused as to when you think Spring should be comparing two instances of a bean one way vs. another (.equals vs. ==).
Please add some more details, if you want to followi this up.
Regards,
Martin Kersten
Aug 17th, 2004, 04:38 PM
Are you puzzled about the term 'prototype'? By prototyping it is just said that everytime you call 'getBean' or refer to the bean a new instance is created according to the prototype specified by the <bean> tags.
It is not the same like query by example or anything like that.
Also you might refer to the Flyweight (/Lightweight) Pattern. By calling it immutable you might want to create only one instance for given property combination or something like that. This can be done by providing your own factory implementation. This is also fairly simple to do.
sjeelani
Aug 17th, 2004, 05:23 PM
Hi,
Thanks for the reply. Since when we say that singleton="true" even though the framework takes care of creating only instance, we can't prevent the user apps from modifying the values. I was looking more at
'Is there a way to tell spring that make mybean in this context immutable and singleton. If we do make the bean immutable programmatically, then I can't use the same bean in other context, where mutability is required.
I was just curious to know that whether we can inject immutable property in particular contexts by allowing the framework to create some wrapper class over the bean to make it immutable.
Thanks,
Jeelani
irbouho
Aug 17th, 2004, 05:34 PM
Jeelani,
You can create an Advisor that throws an exception whenever a method is invoked and apply it to your singleton bean setters methods. This will prevents "accidental" properties changees. I can see, however two issues with this scenario:
1. you can not apply your Advice to public properties.
2. you can not prevent changes to "Object" properties:
myBean.getSubBeans().clear();
All in all, this will work only for "basic" beans. :cry:
davison
Aug 18th, 2004, 06:19 PM
I was just curious to know that whether we can inject immutable property in particular contexts by allowing the framework to create some wrapper class over the bean to make it immutable.
seems an odd requirement but you can still manage it programatically quite well if I understand correctly what you're trying to do and you want to avoid AOP.
public class MyBean {
private boolean immutable = false;
private String propOne;
public void setPropOne(String propOne) {
if (immutable) throw new IllegalAccessException("no way Jose");
this.propOne = propOne;
}
public void makeImmutable() { immutable = true; }
}
Now in your bean definition, make the makeImmutable method an init method..
<bean id="myBean" class="MyBean" init-method="makeImmutable">
<property name="propOne"><value>foo</value></property>
</bean>
Your bean will be made immutable after the bean factory has set the properties on it, but your bean class can still be used elsewhere for mutable instances while ever you don't call the setImmutable() method on it.
irbouho
Aug 18th, 2004, 06:25 PM
public class MyBean {
private boolean immutable = false;
private String propOne;
public void setPropOne(String propOne) {
if (immutable) throw new IllegalAccessException("no way Jose");
this.propOne = propOne;
}
public void makeImmutable() { immutable = true; }
}
this is a nice solution but it does not yet prevents users from calling
MyBean.getSomeObject().setSomeProperty(someValue);
and of course we need here a way to prevents accidental calls to
MyBean.makeImmutable();
davison
Aug 18th, 2004, 06:53 PM
this is a nice solution but it does not yet prevents users from calling
MyBean.getSomeObject().setSomeProperty(someValue);
correct, it was a simple answer to an incomplete set of requirements. The main point being AIUI how to prevent properties being set after the bean factory creates the bean, but without preventing other (non Spring) apps from reusing the class and setting them. In your example above, the accessor can return a clone of someObject.
Cybernet Sauvignon
Aug 19th, 2004, 06:54 AM
Hi,
maybe you were inspired by J2SE Collections.unmodifiebleSet etc. methods. Please notice that for each type of Collection there is a special method/wrapper respectively. A general wrapper can be made only using AOP. And not just the simple DynaProxy solution, but the full blown code manipulation (to disable an access to the public fields).
You have one more possibility. Define your implementing class as real immutable (no direct setters, getters returning clones or immutable collections, ...)
The bean definition can then use just constructor args.
jasonchen_nj
Aug 27th, 2004, 12:33 PM
The flexibility provided by Spring Framework is good. However, as I start introducing it into our project, my tech lead did ask me the following questions,
If it's a "spring singleton" defined in Spring Context, how do you prevent the other developers from doing a "new" manually? :?:
If it's not a "spring singleton”, again, how can you prevent people from just trying the "new" but not “getBean” from the framework? :?:
I think a constructor injection is a necessary. We are also considering making a "non-spring" singleton to access the Spring context in order to prevent this from happening.
Any other suggestion is all welcome.
mperham
Aug 27th, 2004, 03:47 PM
Spring 1.1 has support for factory methods so you can prevent "new" access.
jasonchen_nj
Sep 8th, 2004, 12:25 PM
The final 1.1 is out. :D
However, I couldn't find any announcement or documentation regarding this issue. :(
Is it not so important for most of the people those are using SpringFramework out there? :?
Jason
Colin Sampaleanu
Sep 9th, 2004, 04:44 PM
Factory methods have been fully documented in the beans chapter since about 1.1RC1....
jasonchen_nj
Sep 10th, 2004, 02:54 PM
Let me quote myself here and open the topic again.
The flexibility provided by Spring Framework is good. However, as I start introducing it into our project, my tech lead did ask me the following questions,
If it's a "spring singleton" defined in Spring Context, how do you prevent the other developers from doing a "new" manually? :?:
If it's not a "spring singleton”, again, how can you prevent people from just trying the "new" but not “getBean” from the framework? :?:
I think a constructor injection is a necessary. We are also considering making a "non-spring" singleton to access the Spring context in order to prevent this from happening.
Any other suggestion is all welcome.
I checked the documentation. The "factory method" is mainly for the purpose to define some old type of factory class to be hanlded by the Spring Context. I don't think it can solve the issue. When you provide a "getInstance" instead of "new", the same issue is still there. (in my quote)
Am I right?
The point is how do you prevent them from using a "new" or "getInstance" without using "getBean" to create the bean? Any one else here has the similar concern?
Jason
jbetancourt
Sep 10th, 2004, 06:05 PM
Sounds like a valid concern. If you own and control the developers and users of your beans (that sounds funny) there is no issue, I guess; they have to follow the process and framework.
But, in the real world and in crunch mode, people take shortcuts and stuff.
I don't see any easy solution unless the classes themselves are written to probe their environment.
class FooInContext extends ContextAware......
public FooInContext(){
if( ctx == null) { throw new CreateOutsideContainerException("..."); }
That seems a code smell, now everything is dependent on its environment. Could AOP help here? Use a constructor aspect on a classes' constructors, and this does the context origination check somehow.
Let me quote myself here and open the topic again.
The flexibility provided by Spring Framework is good. However, as I start introducing it into our project, my tech lead did ask me the following questions,
If it's a "spring singleton" defined in Spring Context, how do you prevent the other developers from doing a "new" manually? :?:
If it's not a "spring singleton”, again, how can you prevent people from just trying the "new" but not “getBean” from the framework? :?:
I think a constructor injection is a necessary. We are also considering making a "non-spring" singleton to access the Spring context in order to prevent this from happening.
Any other suggestion is all welcome.
I checked the documentation. The "factory method" is mainly for the purpose to define some old type of factory class to be hanlded by the Spring Context. I don't think it can solve the issue. When you provide a "getInstance" instead of "new", the same issue is still there. (in my quote)
Am I right?
The point is how do you prevent them from using a "new" or "getInstance" without using "getBean" to create the bean? Any one else here has the similar concern?
Jason
feester
Sep 11th, 2004, 11:35 AM
The point is how do you prevent them from using a "new" or "getInstance" without using "getBean" to create the bean?
First, you can't prevent them from using new or a factory getInstance directly. Don't worry about it, because you can easily refactor a bean to instead receive what objects it needs.
Second, why do you think the way you get a reference to an object is via applicationContext.getBean()????
I have a small web application with maybe 70 or so beans and the only time I have used getBean is a few times in my integration testing code. (In production, none of the beans I created have any knowledge of Spring's core APIs) I get impression that you are not using inversion of control--and Spring's capabilities--to it's fullest yet. It appears that your beans are passed an ApplicationContext--why?
The construction of your beans and 'injection' of their dependencies is defined in the context xml files! A bean doesn't have to have any knowledge that it is in a Spring environment. (If you pass the ApplicationContext to it then it would have knowledge of Spring interfaces) All a bean has to know is the interfaces of the objects it needs. Also a bean only has to provide a means for an outside agent--the Spring enviroment--to pass it the object instances it needs. This is done via a constructor or setter methods.
Have you been passing your object dependencies in your xml files? For example:
<property name="velocityEngine">
<refbean="velocityEngine"/>
</property>
In this case there is a property on some bean that has a method called setVelocityEngine( VelocityEngine ) And there is a bean defined somewhere else in context files that has the name or id of "velocityEngine" that is of type VelocityEngine.
The bean in question doesn't know how the object it needs is constructed all it knows is it has a reference to an object of a certain type and knows how to call that objects interface.
Your developers might follow a rule something like following:
"Make sure your primary objects/services provide a means to receive all their dependencies"
The actual construction/instantiation of these beans is handled by a third party--the IOC framework. The Spring framework wires all your system's objects together for you.
While there might be situations where passing ApplicationContext make sense, I think passing an ApplicationContext should be done rarely.
Regards, Jim
vBulletin® v3.7.3, Copyright ©2000-2008, Jelsoft Enterprises Ltd.