Using/converting an XML file to a Spring bean definition - java

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>

Related

Change bean class name at runtime

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?

using a Java blueprint service defintion

I can't get the blueprint right for using a service locally. The OSGi server (karaf) displays GracePeriod and eventually a timeout waiting on ILookupMfgService.
If I remove the reference line the bundle starts and has an ILookupMfgService available.
Any suggestions on what I'm doing wrong?
Thanks for helping with my learning!
Timothy
<blueprint default-activation="eager" xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jpa="http://aries.apache.org/xmlns/jpa/v1.0.0" xmlns:tx="http://aries.apache.org/xmlns/transactions/v1.0.0" xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0"
xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0
http://www.w3.org/2001/XMLSchema-instance http://www.w3.org/2001/XMLSchema-instance
http://aries.apache.org/xmlns/jpa/v1.0.0 http://aries.apache.org/xmlns/jpa/v1.0.0
http://aries.apache.org/xmlns/transactions/v1.0.0 http://aries.apache.org/xmlns/transactions/v1.0.0
http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0 http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0 ">
<!-- implemenation of the service -->
<bean id="lookupMfgServiceStubImpl" class="com.services.jpa.LookupMfgServiceStub" scope="singleton"
init-method="init" />
<!-- create a service with the implementation -->
<service id="lookupMfgServiceStubLocal" ref="lookupMfgServiceStubImpl" interface="com.services.ILookupMfgService" />
<!-- create a reference for injecting into another bean - this line causes the GracePeriod / timeout -->
<reference id="lookupMfgServiceStubRef" interface="com.services.ILookupMfgService" availability="mandatory" ctivation="eager" />
<bean id="EntityImpl" class="com.services.jpa.Entity" scope="singleton" init-method="init">
<!-- use the service - won't work without the reference above being valid -->
<property name="lookupMfg" ref="lookupMfgServiceRef" />
</bean>
</blueprint>
without reference line
karaf#root()> services -p 123
com.server.services (123) provides:
----------------------------------------
objectClass = [com.services.ILookupMfgService]
osgi.service.blueprint.compname = lookupMfgServiceStubImpl
service.id = 932
----
You must not declare a mandatory reference to service exposed in the same blueprint/bundle. The container gets confused because it wants to start a service with a reference to a service that is not yet there (himself) which results in an unrecoverable GracePeriod.
A rough analogy of a reference is a Java Import from another package. The analogy of a service is a public class.
You need the import (=reference) if you want to use a class from a different package.
In your example you do not need the reference because you are within your bundle. You can reference your declared Bean directly instead:
<!-- implemenation of the service -->
<bean id="lookupMfgServiceStubImpl" class="com.services.jpa.LookupMfgServiceStub" scope="singleton"
init-method="init" />
<!-- create a service with the implementation -->
<service id="lookupMfgServiceStubLocal" ref="lookupMfgServiceStubImpl" interface="com.services.ILookupMfgService" />
<bean id="EntityImpl" class="com.services.jpa.Entity" scope="singleton" init-method="init">
<!-- use the service - won't work without the reference above being valid -->
<property name="lookupMfg" ref="lookupMfgServiceStubImpl" />
</bean>
p.s. If no no other bundle needs your LookupMfgService then you can even leave out the service declaration.

Spring Jaxb2Marshaller External Binding File

In Spring, I'm declaring my org.springframework.oxm.jaxb.Jaxb2Marshaller, but I also want to declare an external binding file:
<bean id="myMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="contextPath" value="com.path.to.pojos" />
<property name="jaxbContextProperties">
<util:map>
<entry key="eclipselink.oxm.metadata-source">
<list>
<value>com/path/to/schema/binding.xjb</value>
</list>
</entry>
</util:map>
</property>
<property name="schema" value="classpath:com/path/to/schema/myService.xsd"/>
</bean>
My binding file looks like this:
<jaxb:bindings version="1.0"
jaxb:version="2.0"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:annox="http://annox.dev.java.net"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
jaxb:extensionBindingPrefixes="xjc annox">
<jaxb:bindings schemaLocation="myService.xsd" node="/xs:schema">
<jaxb:globalBindings>
<xjc:javaType name="java.util.Date" xmlType="xs:date"
adapter="com.some.path.to.custom.adapter.DateAdapter" />
</jaxb:globalBindings>
<!-- More Declarations -->
</jaxb:bindings>
</jaxb:bindings>
This setup works fine with XJC to generate the objects from the schema along with the external binding file. But I can't get the appropriate setup for my Spring configuration.
I get the following error:
org.xml.sax.SAXParseException; lineNumber: 9; columnNumber: 77; unexpected element (uri:"http://java.sun.com/xml/ns/jaxb", local:"bindings"). Expected elements are <{http://www.eclipse.org/eclipselink/xsds/persistence/oxm}xml-schema>,<{http://www.eclipse.org/eclipselink/xsds/persistence/oxm}xml-schema-type>,<{http://www.eclipse.org/eclipselink/xsds/persistence/oxm}xml-schema-types>,<{http://www.eclipse.org/eclipselink/xsds/persistence/oxm}xml-java-type-adapters>,<{http://www.eclipse.org/eclipselink/xsds/persistence/oxm}xml-registries>,<{http://www.eclipse.org/eclipselink/xsds/persistence/oxm}xml-enums>,<{http://www.eclipse.org/eclipselink/xsds/persistence/oxm}java-types>
I'm stuck on this, and I really need the binding file to be separate than my schema. I can't find any example of this setup online, I would love an example on how to properly configure an external binding file with the JaxB2Marshaller.
Please let me know if my question is incomplete or if more information is required.
Thanks,
JP
As far as I know, bindings file is only used during the compilation time, to derive Java classes from the XML Schema. So it does not make sense to configure it in runtime, on a marshaller. Neither Spring nor JAXB will consider it. All you could have configured with the bindings file is already in your com.path.to.pojos.* classes.

Spring configuration files: package imports or names in attribute values

All the examples I've seen so far about Spring configuration have
<bean class = "org.example.complex.package.path.FooClass" >
I wonder if this can be simplified through a mechanism similar to Java imports, something like:
<beans ...>
<import name = "org.example.complex.package.path.FooClass" />
<import name = "org.example.another-package.*" />
<bean class = "FooClass" >...</bean>
<bean class = "AnotherClass">...</bean>
</beans>
Alternatively (or in addition), does XML support namespaces in attribute values? Something like:
<beans xmlns:foo="org.example.complex.package.path." ...>
<bean class = "foo:FooClass" ...>
...
I would need this for other purposes too (e.g., working with RDF's URIs). My understanding is that this is supported by some software, but not a standard XML feature.
No way. Spring uses import tag to import / add another beans definition xml file to the current context.

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