Change bean class name at runtime - java

we have bean defined in one project as below:
<bean class="a.b.c.d.classA" id="classA">
<property name="prop1" ref="ref1"/>
</bean>
We are importing this configuration in another project and want to overwrite bean definition during patch installation.
So, here we need change class but other details will keep as it is (no change in bean id).
<bean class="a.b.c.d.classB" id="classA">
<property name="prop1" ref="ref1"/>
</bean>
With patch install XML file , we thought to do it using ant call like this:
<xmltask source="beans.xml" dest="beans.xml">
<remove path="/beans/bean[#id='classA']/#class"/>
</xmltask>
<antcall target="abcd">
<param name="file_path" value="beans.xml"/>
<param name="item.path" value="/beans/bean[#id='classA']"/>
<param name="item.name.path" value="class"/>
<param name="item.name.value" value="a.b.c.d.classB"/>
</antcall>
Above approach is somehow not working, may be missing something. So, what changes can we do?

Related

Yguard does not modify my classnames properly (with the obfuscated ones)

I'm trying to obfuscate a JAR file using the yguard 3.0.0 maven plugin. The obfuscated JAR is as almost as expected, it is shrinked and with all the private methods and variables renamed. I need that package names will be renamed too and this is performed, but the spring XML files needed to start my Tomcat are not being updated with the obfuscated packages.
My ant task is the following:
<configuration>
<tasks>
<property name="runtime-classpath" refid="maven.runtime.classpath"/>
<taskdef name="yguard" classname="com.yworks.yguard.YGuardTask" classpath="${runtime-classpath}"/>
<yguard>
<inoutpair in="C:/test/webapp.jar" out="C:/test/webapp_obfuscated.jar" />
<shrink>
<property name="error-checking" value="pedantic"/>
</shrink>
<rename>
<adjust replaceContent="true" replaceName="true">
<include name="ApplicationContext.xml"/>
</adjust>
</rename>
</yguard>
</tasks>
</configuration>
Note that here in my example, I'm only trying to deal with the ApplicationContext.xml, but this file remains with the same classnames that the no obfuscated version. I'm sure that the yguard task is doing something into my ApplicationContext.xml because I have a tag in the file and the path to a file is properly obfuscated but the classnames and the other stuff no:
<!-- Properties ldap -->
<bean id="ldapProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean" scope="singleton">
<property name="ignoreResourceNotFound" value="true"/>
<property name="locations">
<list>
<value>classpath:A/A/B/E/ldap.properties</value> <--Obfuscated!-->
</list>
</property>
</bean>
<bean id="authenticationBO" class="com.grifols.grb.authentication.bo.AuthenticationBO" scope="singleton">
<property name="dbAccess" ref="dbAccessGRB"/>
<property name="usersSecurityBO" ref="usersSecurityBO" />
<property name="settings" ref="settings" />
<property name="ldapProperties" ref="ldapProperties" />
</bean>
According to the Yguard documentation I think that I only have to use replaceContent="true" and detail which file but I'm not
Any idea? I really appreciate any help you can provide.
Ivan
yGuard is able to replace either file/path names or class names in resource files, but not both at once.
I.e.
<adjust replaceContent="true">
will adjust
<example>
<class>com.yworks.yguard.StringReplacer</class>
<file>com/yworks/yguard/StringReplacer.properties</file>
</example>
to
<example>
<class>com.yworks.yguard.StringReplacer</class>
<file>A/A/A/SR.properties</file>
</example>
With
<adjust replaceContent="true" replaceContentSeparator=".">
the result will be
<example>
<class>A.A.A.SR</class>
<file>com/yworks/yguard/StringReplacer.properties</file>
</example>
However, the desired result
<example>
<class>A.A.A.SR</class>
<file>A/A/A/SR.properties</file>
</example>
is not (yet) supported.

Ant Multiple Property Values with the Same Name

I am working on an ant build script. How do i set the two property value with the same name:
<property name="java.src.dir" location="src" />
<property name="java.src.dir" location="src/java" />
In my application some of the directories are src/java and some are src. I need to make it flexible enough to work on both.

log4j2 how to read property variable from file into log4j2

Background: As usual we have various life cycles like dev. stage, lt, prod all these are picked at deploy time from environment variable ${lifecycle}.
So JNDI setting we stores in ${lifecycle}.properties as variable datasource.jndi.name=jdbc/xxx. As other beans are also using this properties file, it is verified that such variable is loaded & file is in classpath, but somehow I am not able to consume this variable in log4j2.xml in below JDBC Appender.
<JDBC name="DBAppender" tableName="V1_QUERY_LOG" bufferSize="4" ignoreExceptions="false">
<DataSource jndiName="${sys:datasource.jndi.name}" />
<Column name="event_date" isUnicode="false" isEventTimestamp="true" />
<Column name="log_level" isUnicode="false" pattern="%level" />
<Column name="logger" isUnicode="false" pattern="%logger" />
<Column name="message" isUnicode="false" pattern="%message" />
<Column name="exception_msg" isUnicode="false" pattern="%ex{full}" />
</JDBC>
I have tried some option like "${datasource.jndi.name}" too, or is there any way I can fit the solution in
<Properties>
<Property name="datasource.jndi.name">get datasource.jndi.name from {lifecycle}.properties</property>
</Properties>
If you are not using java system properties, but environment variables, you should not use the ${sys:variable} prefix, but the ${env:variable} prefix instead. See also http://logging.apache.org/log4j/2.x/manual/lookups.html#EnvironmentLookup
In general the placeholders that work in Spring bean configuration files do not work in Log4j configuration. They look the same, but the syntax and underlying discovery mechanism are completely different.
For instance ${sys:something} attempts to resolve a Java system property. System properties are usually passed to JVM as command line arguments in format -Dkey=value and not stored in property files.
You can try to use Resource bundle syntax ${bundle:MyProperties:MyKey} however this will load from that specific file and will not perform any additional Spring substitutions.
See also:
http://logging.apache.org/log4j/2.x/manual/configuration.html#PropertySubstitution

Using/converting an XML file to a Spring bean definition

I have defined a Spring application context xml which will be edited by end users to add new beans.Something like:
<bean name="myBeanName1" class="com.xxx.Yyy">
<property name="type" value="type1" />
<property name="name" value="name1" />
<property name="arguments" value="arg1" />
</bean>
<bean name="myBeanName2" class="com.xxx.Yyy">
<property name="type" value="type2" />
<property name="name" value="name2" />
<property name="arguments" value="arg2" />
</bean>
.
.
.
Now I am asked to change this to a normal xml so that users wont be bothered by bean property and class names:
<def name="Name1">
<type>type1</type>
<argument>arg1</argument
</def>
<def name="Name2">
<type>type2</type>
<argument>arg2</argument
</def>
As my code is using the bean, how can I use the new xml with minimal code change so that it is converted to a bean definition as earlier and things work as before?.
I dont know if Spring has a solution for this out of the box. What I thought was applying stylesheet to the new xml to create my older bean. Any other better/elegant solution for this?
Edit: Now that user input is not inside the bean anymore, is it possible to use the new xml to inject to a #Component class?
Spring supports creating custom tags. You need to create xsd schema, NamespaceHandlerm, implement BeanDefinitionParsers and make spring aware of these by creating spring.handlers & spring.schemas special files.
Have a look at Extensible XML authoring
Example:
<beans xmlns declaration goes here>
<yournamespace:yourcustomtag id="some id">
<yournamespace:some_other_tag your-custom-attribute="some value" />
</yournamespace:yourcustomtag>
</beans>

How to use property-placeholder for file on filesystem

We used to have a way to load properties from a file on the classpath:
<context:property-placeholder location="classpath:myConfigFile.properties" />
and it worked great. But now we want to load properties from a specific file on the system that is NOT in the classpath. We wanted to be able to dynamically load the file, so we are using a Java environment variable to populate it. I'll give a simple example below:
In Java:
System.setProperty("my.prop.file", "/path/to/myConfigFile.properties");
In Spring XML:
<context:property-placeholder location="${my.prop.file}" />
I've also tried it this way, thanks to an idea from Luciano:
<context:property-placeholder properties-ref="prop" />
<util:properties id="prop" location="reso"/>
<bean id="reso" class="org.springframework.core.io.FileSystemResource">
<constructor-arg index="0" value="${my.prop.file}" />
</bean>
Everything I've tried has failed. No matter what I set my.prop.file to. Greatest hits include:
<context:property-placeholder location="/path/to/myConfigFile.properties" />
(ClassNotFoundException: .path.to.myConfigFile.properties)
<context:property-placeholder location="file:/path/to/myConfigFile.properties" />
(ClassNotFoundException: file:.path.to.myConfigFile.properties)
<context:property-placeholder location="file:///path/to/myConfigFile.properties" />
(ClassNotFoundException: file:...path.to.myConfigFile.properties)
How do you use property-placeholders with a location that is on the file system and NOT on the classpath? We are using Spring 3.0.5.
It turns out there was a problem with the script running the Java program that loads the spring file. Thank you for helping. I am going to request that this question be deleted, as the original code works after all.
Thank you for your help.
This did work for me:
<context:property-placeholder location="file:/path/to/myConfigFile.properties" />
But this (interestingly) did not:
<context:property-placeholder location="#{ systemProperties['foo'] }" />
I got
java.io.FileNotFoundException: Could not open ServletContext resource [/#{ systemProperties['foo'] }]
You're not going to be able to use a property placeholder ${..} with the definition of a PropertyPlaceholderConfigurer. It's the chicken before the egg.
You can always subclass PropertyPlaceholderConfigurer and have it do whatever you want (for example, call setLocations() in a #PostConstruct method. Then, instead of using <context:property-placeholder>, use:
<bean class="com.foo.MyPropertyPlaceholderConfigurer"/>
What about this way?
<context:property-placeholder properties-ref="prop" />
<util:properties id="prop" location="reso"/>
<bean id="reso" class="org.springframework.core.io.FileSystemResource">
<constructor-arg index="0" value="/yourpathandfile" />
</bean>

Categories