Generate Spring bean definition from a Java object - java

Let's suggest that I have a bean defined in Spring:
<bean id="neatBean" class="com..." abstract="true">...</bean>
Then we have many clients, each of which have slightly different configuration for their 'neatBean'. The old way we would do it was to have a new file for each client (e.g., clientX_NeatFeature.xml) that contained a bunch of beans for this client (these are hand-edited and part of the code base):
<bean id="clientXNeatBean" parent="neatBean">
<property id="whatever" value="something"/>
</bean>
Now, I want to have a UI where we can edit and redefine a client's neatBean on the fly.
My question is: given a neatBean, and a UI that can 'override' properties of this bean, what would be a straightforward way to serialize this to an XML file as we do [manually] today?
For example, if the user set property whatever to be "17" for client Y, I'd want to generate:
<bean id="clientYNeatBean" parent="neatBean">
<property id="whatever" value="17"/>
</bean>
Note that moving this configuration to a different format (e.g., database, other-schema'd-xml) is an option, but not really an answer to the question at hand.

You can download the Spring-beans 2.5 xsd from here and run xjc on it to generate the Java classes with JAXB bindings. Then you can create the Spring-beans object hierarchy on runtime (and manipulate it as you wish) and then serialize it to an XML string using the JAXB Marshaller as shown in Pablojim's answer.

I'd use Jax-b to do this. You'de create a bean object with a list of property objects inside.
#XmlRootElement(name = "bean")
#XmlAccessorType(XmlAccessType.FIELD)
public class Bean {
#XmlAttribute
private String id;
#XmlAttribute
private String parent;
#XmlElement(name="property")
private List<BeanProperty> properties
Then You'd need to also add annotations to BeanProperty. Then when you have a populated object simply marshal it to xml using jaxb:
Marshaller m = jc.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.marshal( myBean, System.out );
For full code examples see: http://java.sun.com/webservices/docs/2.0/tutorial/doc/JAXBUsing.html
Alternatively you could use Groovy - you can drop it in place and creating this xml would be very simple... : http://www.ibm.com/developerworks/java/library/j-pg05199/index.html

If you want a simple to implement, no work solution, you can look at the IDE support provided in IntelliJ and Eclipse (The Spring Tool Suite).
They parse all the bean files (you can configure which set) and inspect the java code so it knows which classes there are, which properties are in those classes. Everywhere you can use Ctrl-Space to help with the options, etc...
I imagine you could setup 'projects' w/o Java code and only the spring config files in order to reduce the learning curve of front line personnel who must make these changes.

What you need is obviously a factory for your neatBeans.
In Spring, instead of declaring a bean, you can declare a FactoryBean whose role is to actually create and configure your final bean.
The NeatBeanFactoryBean could read a property file (or xml configuration) to determine how to configure the produced neatBeans, depending on some runtime parameter (the current clientID for example) or compile-time parameter (environment variable).

To add to the other two questions, I believe Spring already has a working model for bean definitions (see org.springframework.beans.factory.config.BeanDefinition); you could base your work on that.

I'd suggest using
<context:property-placeholder location="classpath*:clientX.properties"/>
and then in your bean def:
<bean id="${clientYNeatBeanId}" parent="neatBean">
<property id="whatever" value="${whateverValue}"/>
</bean>
Then for each client you can have a clientX.properties containing
whateverValue=17
whateverAnotherValue=SomeText
.properties files are easier to edit both manually, and programaticalyl via java.util.Properties store(..) / save(..) methods

Related

Changing single parameters in XML file wrapped as Java Object

I am getting a config.xml file via a REST API which has a specific structure. I am adapting this config.xml via Java and pushing it again via PUT command to the REST endpoint to update it.
This XML structure contains the same amount of properties (let's say 'name' and 'description') but might be enhanced by some more properties (e.g. 'category'), which I am not aware of.
<config>
<name>myName</name>
<description>myDescription<description>
<category>myCategory<category>
</config>
My goal is to adapt this config file via Java Code while wrapping it into an Object. So I built a Class 'Config' containing 'String name' and 'String description'.
I can easily parse the config.xml to my Config object with JAXB and adapt name and description, but when marshalling it to XML the category would be missing, although it was returned by the REST API. Is there a way (maybe ValueChangeListener?) to adapt only the changed values in an existing xml file?
public class Config { String name; String description; }
So I don't event want to be able to change 'category' at all, I just don't want to lose the data.
Info: In my scenario the Config class is very complex and has alot of subclasses (it's a representing a Jenkins Job). So the example above is very simplified.
I got the idea to create a second config file, only having the changed parameters. Afterwards merging the to config files. But I had no idea how to be aware what exactly has changed and how to implement it.
Example:
I want to change description to "newDescription", so my expected XML would be:
<config>
<name>myName</name>
<description>newDescription<description>
<category>myCategory<category>
</config>
unfortuntately it is:
<config>
<name>myName</name>
<description>newDescription<description>
</config>
Means category parameter is lost, as I am not aware of it and therefore didnt add it to the Config class. Summarized, there might be parameters in the XML file which I am not aware, which I also do not want to change - but don't want to lose when pushing an updated config.

Creating a network of objects from custom XML config with Spring

I have a custom XML config defining a kind of network like this
S1 ---- O1 ---- O2 ---- O3 ---- T1
\
+--- O4 ---- O5 ------------ T2
\
S2---+- O6 --+- O7 ------------ T4
/ /
S3-+ /
/
S4 ------+
Where
S is some kind of data source, like a web socket
O is an operator processing the data
T is the target or data sink
These elements are represented with xml blocks like this:
<source name="S1" address="ws://example/1" type="websocket" dataType="double" />
<operator name="O6" type="threshold">
<input name="S1"/>
<input name="S2"/>
<input name="S3"/>
<property name="threshold" value="10.34" />
<property name="window" value="10.0" />
</operator>
<sink name="T1" type="database">
<input name="O3"/>
</sink>
The dependencies are constructor parameters. My example operator O6 would have a constructor like this:
class ThresholdOperator extends Operator<Boolean> {
public ThresholdOperator(
String name, // "O6"
List<DataSource> sources, // [S1, S2, S3]
double threshold, // 10.34
double window) { // 10.0
...
There could be multiple instances of this class with different constructor parameters. It is possible that a class has more than one constructor. The type parameter of the base class is the output type.
The type attribute determines what concrete class has to be instantiated. The dataType attribute of the source decides which kind of converter (here String to Double) should be injected.
To create the instances I need to figurare out a dependency graph and start instantiating the objects without other objects from my graph as dependency (the sources in this case), then I would create the objects which depend only on objects created in the first step and so on.
So I would basically reinvent something like Spring for my special use case. Is there a way to leverage Spring to create and wire objects in my case? A somewhat crude hack would be to transform my xml config to a beans.xml. But maybe there is a better way using BeanFactory or the like. Or would it be possible to create the Spring meta-model directly?
I'm using Spring 4.3 but the RC of Spring 5 could be an option, if it would help.
Another alternative not yet mentioned here is using XSLT.
The idea is to define xsl that maps your domain-specific xml to spring beans xml (XSLT+XPath should be more than enough to cover your case).
You can then read domain-specific xml, transform it with that xsl and feed the result to spring.
Have a look on StaticApplicationContext. It is stated in the docs that it is:
Mainly useful for testing.
... but it is a full fledged application context that has support for programmatic bean registration.
You can read your domain-specific xml and define beans based on it inside StaticApplicationContext.
This blog post can give you an idea on how to use StaticApplicationContext to define beans with references and constructor args.
A simpler approach to instantiate your objects from the document would be to either
create an XML Schema describing your data format and using JAXB to create your Java classes
annotate your existing Java classes with JAXB annotations
The "crud" hack approach may be a better approach but instead of converting your config xml to beans xml file manually, I suggest you to look at the Extensible XML authoring approach.
The configuration parser, a.k.a. bean definition parser, allows you to build the bean definitions which will eventually be used your application's spring context to instantiate the beans.
This should also eliminate the needs of figuring out the dependency hierarchy manually and instantiation of objects yourself.
Hope it answer your question.

How to structure Spring code for JAXB marhalling and proccessing of XML

The Question
I'm new to Java and spring and I'd like to know how to structure code which marshals different objects from XML and then processes them. I'm converting some code JAVA code from before my time to use spring. I know the way I've approached this this probably, wrong but If someone could offer a few pointers on how to restructure things "the Spring way" that would help alot. I've read a lot of the Spring docs, but I'm finding it hard to apply what is in there to my code.
The Situation
I'm not going to post the whole code tree as even and simple example is a lot of code (which is the problem). So I'll just describe the method.
I've got XML and schemas for two classes CLASSA & CLASSB. I've generated JAVA wrappers using xjc. I've got a JAVA class which is a wrapper for the JAXB marshaller. The wrapper needs to be given the class name and the package name of the class to be marshalled on construction.
public JaxbWrapper(String ClassName, String packageName) throws ClassNotFoundException, InstantiationException,
IllegalAccessException, JAXBException
{
this.packageName = packageName;
// set the context is the expensive operation
setJAXBContext(Class.forName(fullJaxbClassName(ClassName)).newInstance());
// get the schma from preset schema dir
schemaFileName = findSchema(ClassName);
myMarsheller = jc.createMarshaller();
myMarsheller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
}
I've then got one bean for each instance of the JaxBWrapper for both ClassA and ClassB. They are almost identical so only the one for class A is shown.
<bean id="jaxbParser_CLASSA" class="org.test.JAXB.JaxbWrapper"
lazy-init="true" scope="prototype">
<constructor-arg index="0" type="java.lang.String"
value="CLASSA" />
<constructor-arg index="1" type="java.lang.String"
ref="testPackage" />
<property name="encoding" ref="xmlEncoding" />
</bean>
Unhelpfully the XML files I have to process are delivered one at a time in file with a fixed name and a rolling counter (and I cannot change that). So I'm unable to tell what object is in the file from the filename. I've have a tiny utility function which check which the object type is in the file I'm trying to process.
I then have the following function:
public static Object loadXML(String xmlFile, String fileName) throws Exception
{
InputStream iStream = XmlUtils.openFile(xmlFile);
String xmlObjectType = XmlUtils.getObjectTypeFromXML(xmlFile);
// get the right JAXB processor
JaxbWrapper jaxB = myContext.getBean("jaxbParser_" + xmlObjectType , JaxbWrapper.class);
Object obj = jaxB.objectFromXML(iStream, xmlObjectType , fileName);
return obj;
}
So I'm taking the object name and getting the right bean from the context. This means I could use things like Spring's object pool to hold lots of JaxbWrappers for different objects. However the way I've implemented this feels wrong to me. I don't like the myContext.getBean("jaxbParser_" + xmlObjectType method of getting the JaxbWrapper bean.
So my question is: Is there a better way of structuring this code? A few simple pointers would be very much appreciated.
Additional Complexity
This is where things, at the moment, become really unmanageable. Once the marshaling stage has completed I've got a post processing stage where there are several different post processor for each class type. I've got Spring beans for each of these and I'm getting them from the application context using:
myContext.getBean(xmlObjectType + "_" + processorType + "_" + xmlObjectType);
where:
xmlObjectType is a string CLASSA or CLASSB which is set by reading the object type from the file (as above).
processorType is s string which is set from the comand line.
To set the proceesorType I'm doing something like the following when the application starts.
if (line.hasOption("file"))
{
processorType = "FileProcessor";
}
if (line.hasOption("print"))
{
processorType = "PrintProcessor";
}
Again, I don't think this is the right way to do things, but It's the best I've got at the moment :-(.
I guess the more general question is how do JAXB and Spring work together? In the real world I have lots very large and complex CLASSA and CLASSBs. I've got java classes for these generated by xjc. As I'm using xjc I have to use jaxb (I guess). The question is how to do that in the Spring world.
Or can I get rid of JAXB and use a spring component. I'd need to use something else to generate all the classes other than xjc. But I cannot find anything that would perform that task
There is a lot of stuff going on here and I have to agree with #BlaiseDoughan you should be able to do this outside of Spring.
Although Spring does do object pooling (aop) and has some management for throw away objects you should not use it for such. Basically anytime your doing getBean during runtime unless your know what your doing your doing it wrong.
Spring is for managing behavior based singletons.
So what you want to do is think how can make a singleton that does the behavior... In your case you want to make a Factory of JaxbWrapper.class (and I don't mean Spring's special bean Factory).
So something like:
public class JaxbWrapperFactory {
Map<String, JaxbWrapper> pool = new ConcurrentHashMap(); // recommend Guava's Cache
public JaxbWrapper create(String ClassName, String packageName) throws ClassNotFoundException, InstantiationException { }
public Object loadXML(String xmlFile, String fileName) throws Exception {
/// use create from above
}
}
Now in Spring you can only wire JaxbWrapperFactory.
If you want to make different strategies for create JaxbWrapper based on the input xml you could make sort of strategy interface and wire in the implementations. But I don't think you need that complexity.
Basically to boil it down these tips:
Be-aware that singletons and most spring managed beans must be thread safe.
Reserve public static methods for utility only as this leads to evil singletons.
Often times for object creation its best to make your own factory pattern.
You might want to take a look at JAXB's factory support.

Spring Dependency Injection beyond the basic tutorials

In my main() method I create a PersonCollection Object using Spring and then I start to load different Persons objects.
BeanFactory appContext = new ClassPathXmlApplicationContext("cp-beans.xml");
PersonCollection pc = appContext.getBean(PersonCollection.class);
Person aPerson = pc.loadById(1);
aPerson.doSomething();
aPerson.loadById(1067);
aPerson.doSomething();
In turn PersonCollection.loadById() can load the object from memcached or from Amazon SimpleDB:
public Person loadById(int id) throws ConnectException, NoSuchElementException {
String memCacheKey = "Person-" + id;
Person aPerson = (Person) cache.get(memCacheKey);
if (aPerson != null) {
return aPerson; //cache hit
}
aPerson = loadByIdFromSdb(id); //cache miss, read it from SimpleDB
cache.set(memCacheKey, aPerson);
return aPerson;
}
So there are two ways to create a Person, the first is deserializing from memcached, the second will call new Person() and assign all data.
Person has two #Autowired properties and is declared as a #Service and the package is in context:component-scan, however the dependencies are not passed, because the bean is created with new or from the cache and not with the Spring framework.
I could use appContext.getBean() to create the Person Object, however, it would mean to pass around the applicationContext and use getBean() inside the application, which doesn't feel right.
How to solve the problem?
UPDATE: I read the documentation and tried the suggestion of Ryan Stewart and wrote a small example project to try it. It works great, thank you!
https://github.com/stivlo/spring-di
Ultimately, I've refactored my original project, in a way that I don't need this feature anymore, but is a good tool to have in my arsenal.
Yes, avoid ApplicationContext.getBean() in your (non-infrastructure) code like the plague.
Option one: Don't autowire your POJO-like classes. Pull that out into a "service" object that is tightly coupled to the Person. This is more or less the current mainstream approach, and I hope it goes away because it gets messy.
Option two: Use AspectJ weaving with the #Configurable annotation to make Person autowirable regardless of where it's instantiated. I really like this option, though I haven't used it in a production project yet.
You may also want to look into a little oddball utility class called ObjectFactoryCreatingFactoryBean, which is a way of "reusing" the capabilities of the BeanFactory without unduly contaminating your business code with worrying about bean names.
<beans>
<bean id="PersonCollection " class="com.example.PersonCollection">
<property name="personMaker" ref="PersonMaker"/>
</bean>
<bean id="personPrototype" class="com.example.Person" scope="prototype">
<!-- Things to inject onto a newly-made person -->
</bean>
<bean id="PersonMaker" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
<property name="targetBeanName"><idref local="personPrototype"/></property>
</bean>
</beans>
In this way, your PersonCollection instance doesn't need to know any bean names, but can get a fresh Person (with the specified dependencies injected) via:
Person p = (Person) this.personMaker.getObject();
IMO there are some ways it could be made much more convenient (such as working with an inner bean rather than idref) but that would require some Spring-guru and a custom XML namespace.

JAX-WS and Enunciate - How to change Enunciate's default XSD naming convention

I'm using Enunciate to generate a SOAP endpoint for a Wicket web application I am working on and I have a couple of questions that I haven't figured out the solution to yet.
1 How do I change the name of the xsd files? I've looked through the FAQ and it tells me to do something similar to this:
<xml>
<schema namespace="http://api.example.com/data" file="data.xsd"/>
</xml>
However, I haven't quite figured out how to set the targetNamespace for my data objects. I've done this for my service via #WebService ( targetNamespace="blah" ), but how do I annotate my data objects to let Enunciate know which namespace they should belong to?
2 Enunciate generates my XSDs just fine, but I don't particularily like the element names it uses. I have a ServiceRequest and ServiceResponse object. The ServiceRequest object has a List of User objects. The ServiceResponse has a list of Group objects. Enunciate suggests that every "User" object within the ServiceRequest should be using the tag "<users>". I feel that it would make more sense to use the singular form, "<user>" since the tag does in fact only contain a single user. Is it possible to change this behaviour, and if so, how?
Thanks in advance.
So just to be clear, with the exception of the question about naming your schema files, your questions are really more about JAXB than they are about Enunciate. JAXB is the spec that defines how your Java objects are (de)serialized to/from XML and Enunciate conforms to that spec.
Anyway, the easiest way to apply a namespace to your Java objects is with a package-info.java file in the package of your Java classes. Annotate your package with #XmlSchema and set the namespace to be the value you want.
Customizing how your accessors are serialized to/from XML can be done with the #XmlElement annotation, e.g.:
public class MyClass {
...
#XmlElement (name="user")
List<User> users;
...
}
Here are the JAXB javadocs
https://jaxb.dev.java.net/nonav/2.1.9/docs/api/
Or google for a good JAXB tutorial.

Categories