Setting sub-property of a Spring bean - java

Is it possible to set a Spring bean sub-property using dot notation? For instance:
<bean name="rememberMe" class="com.mydomain.security.RememberMeManager">
<property name="cookie.domain" value=".${webRoot}"/>
</bean>
Or do I need to also create an intermediary bean for the Cookie object stored in RememberMeManager.getCookie()?
My objective is to set cookies set by my site to ".mydomain.com" instead of "mydomain.com". I have a properties file with webRoot=mydomain.com in it.

Spring's PropertyPlaceholder will have no problem with replacing placeholders that are substrings of the property/value, such as ".${webRoot}", and according to the documentation, it will also fallback to the system properties if no property in the properties file is found.
Did you try this? Does it work or not?

Related

database connection using c3p0

Currently in my project the datasource , transactionmanager and other bean required for database connectivity are defined in xml file and there values are configured in property file from which it takes to do the connection.
for ex:
<bean id="DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close" p:driverClass="${DRIVER_CLASS}" p:jdbcUrl="${DB_URL}"
p:minPoolSize="${MIN_DB_POOL_SIZE}" p:maxPoolSize="${DB_POOL_SIZE}"
p:maxStatements="${DB_POOL_SIZE}" p:idleConnectionTestPeriod="${IDLE_CONNECTION_TEST_PERIOD}"
p:loginTeimeout="${LOGIN_TIMEOUT}" scope="singleton"></bean>
ALL these like values ${DB_POOL_SIZE} are configured in property file.
the class com.mchange.v2.c3p0.ComboPooledDataSource is final class and can't be extended. so my requirement is
:when spring create the bean of Datasource i should be able to set the value of the variable in xml(DB_URL) from my java file through setter method.
how to do that?
I don't quite get what you are trying to do, but if your problem is that you'd like to extend ComboPoolDataSource with some custom functionality, just extend AbstractComboPooledDataSource. Check out the source to ComboPooledDataSource. There's not much there (once you get past the annoying copyright header). Use that as a template, and extend AbstractComboPooledDataSource however you'd like.

Spring PropertyPlaceholderConfigurer Default Value overwriting actual property value

I have a bean which is populating properties using the #Value annotation like this
#Value("${propbean.value : 'None'}")
private String value;
In my application context I have the following configuration
<bean id="propbean"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="file:${path}/values.properties"
p:ignoreResourceNotFound="true"
p:ignoreUnresolveablePlaceholders="true" />
When the values.properties file is not present, the defaults 'None' are being set as expected, however when the properties file is present, the default values are still being used, even though I receive a log message that the properties file was loaded from the PropertyPlaceholderConfigurer
190315 14.23.44,517 {} {} {} INFO (PropertiesLoaderSupport.java:172) Loading properties file from URL [file:/path/to/file/values.properties]
I need the default values to take effect only when the properties file is missing and/or the placeholders are not resolveable; not all the time. I have also tried using SPEL, but because this is a PropertyPlaceholderConfigurer object as opposed to using the directive the SPEL solution doesn't work for me. It's my understanding that when using the ${value : default} format for placeholders that the default is only substituted when the value is null, however if I remove the " : 'None'" from the value placeholder the property resolves correctly!
Hopefully this helps someone in the future - the problem was the p:ignoreUnresolveablePlaceholders="true" property in the bean definition. Apparently that instructs Spring to ignore the properties being read into the bean altogether no matter what if there is a default value set.
Removing the property/setting to false resolves the problem completely.

java spring context:property-placeholder - set properties paths from placeholder

<context:property-placeholder
location="a.properties,b.properties"
ignore-unresolvable="true"/>
result: both properties file are loaded
<context:property-placeholder
location="${properties_location}"
ignore-unresolvable="true"/>
where properties_location is "a.properties,b.properties"
result: Exception in thread "main" org.springframework.beans.factory.BeanInitializationException: Could not load properties; nested exception is java.io.FileNotFoundException: class path resource [a.properties,b.properties] cannot be opened because it does not exist
edit: ${properties_location} is set the following way:
System.getProperties().setProperty("properties_location", "a.properties,b.properties");
ApplicationContext ctx = new GenericXmlApplicationContext("context.xml");
...
How can I initialize my application the 2nd way? to have all the properties file's path defined in a placeholder.
You have to change this to:
<context:property-placeholder
location="classpath:a.properties,
classpath:b.properties"
ignore-unresolvable="true"/>
From the source of the parser for the property-placeholder element.
String location = element.getAttribute("location");
if (StringUtils.hasLength(location)) {
String[] locations = StringUtils.commaDelimitedListToStringArray(location);
builder.addPropertyValue("locations", locations);
}
First the location is retrieved, if that has a value it is converted to a String[]. Springs conversion service takes care of replacing any placeholders in the String[]. But at that moment the properties_location placeholder is just a single element in the array and that gets resolved to a.properties,b.properties without further processing.
So at the moment this isn't possible with placeholders I'm afraid.
One thing that might work is using SpEL if it is always going to be a system property you can use #{systemProperties['properties_location']} to resolve the value. That should be resolved before anything else.
You cant use a property placeholder as a value in a placeholder placeholder resolver. Its like saying, "hey, resolve the placeholder for the location of the all the properties, and then you can start resolving properties!".
Logically it just dosent make sense. I was experimenting with spring property placeholder resolution recently, and stumbled upon this same question. I attempted to use two property placeholder configurers, one to resolve the location of the properties for the second, and the second to resolve the rest of the properties. Of course this dosent work due to the way in which spring initialises its beans.
Initialise bean post processors
Construct them
Construct all other beans
Since the property placeholder configurer is a bean post processor, if you have more than one of them, they get initialised and constructed at the same time, so know nothing of each others properties at construction
Edit
Given that the property location is a system property you could have:
System.getProperties().setProperty("properties_location_a", "classpath:/a.properties");
System.getProperties().setProperty("properties_location_b", "classpath:/b.properties");
And then in your spring content.xml:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders" value="true"/>
<property name="locations">
<list>
<value>${properties_location_a}</value>
<value>${properties_location_b}</value>
</list>
</property>
</bean>

How to inject all properties from Spring into a bean?

I want to inject a map containing all the properties that spring knows of (which are inserted by a library) to a config class that I have through the spring xml. Is that possible?
<bean class="Config">
<constructor-arg name="env">
<map>
//inject all properties?
</map>
</constructor-arg>
</bean>
Why don't you just inject the Spring Context? Through the Context, you can look up any bean via its name.
Edit:
From this answer, you could also use the following:
<bean class="Config">
<constructor-arg name="env">
<util:properties location="${path.to.properties.file}"/>
</constructor-arg>
</bean>
Where your "env" constructor argument is a java.util.Properties object.
For later versions of Spring (including spring-boot) that support the injection of an Environment you can use this to access all properties loaded.
To answer this question inject a AbstractEnvironment so that you are able to call the getPropertySources() method that will allow you to see where the properties have been loaded from (e.g. a file, OS variables, etc)
#Autowired
public Config(AbstractEnvironment environment)
{
MutablePropertySources propertySources = environment.getPropertySources();
// inspect propertySources to see all properties loaded by Spring
}
Can you not extend the library class that you use and instantiate your bean instead of the default library one? Then you would be able to inspect all the values.
Otherwise, if you know the signature of the library, you can always use AOP to weave some code around the library and get access to the properties there. A bit more complicated, but still gets you where you need to go. You can definitely use AspectJ (which requires a little more config) or even Spring AOP, depending how things are being accessed.
If you want/need more insight on this, let me know.

Making a spring bean dynamically refer to two classes based on a system property in Spring 3.0

I am trying to achieve the below functionality using Spring but have not succeeded till now.
Create a spring bean "testBean" in XML file and dynamically point it to class "A" or "B" depending on whether some system property "C" has been set or not. I want to handle this at the XML configuration file level itself. The rest of the application should be able to use the bean "testBean" seamlessly.
Please let me know how can this be done using Spring? Let me know if any other details are required.
Thanks in advance.
Use bean profiles to achieve this
Also See
is-there-any-way-to-enable-or-disable-the-spring-bean-definition-in-applicationcation
You could use the expression language to configure your testBean like this (not tested):
<bean id="testBean" class="com.test.TestBean">
<property name="pointer" value="#{ systemProperties['C'] != null ? 'com.test.A' : 'com.test.B' }"/>
</bean>
See the documentation for further reference.
Relevant parts:
6.4.1 XML based configuration
6.5.13 Ternary Operator (If-Then-Else)

Categories

Resources