Jacn has been tested with
The build process will use jarjar to embed ASM into the distribution, to avoid potential version conflict.
To run the test cases you'll also need (already in the lib directory of the source tree):
cvs -d :pserver:anonymous@jacn.cvs.sourceforge.net:/cvsroot/jacn co jacn-core
ant
ant test
You can start by study the following little applicationm, which is a complete Spring/Jacn application, all in a single compilation unit. The configuration part happens in the inner Jacn_foo class. This class is loaded by the JacnApplicationContext to extract the meta-information about constructing the managed beans ( the fields of the configuration class).
ConvertUtil.jacn2Xml() is used to quickly dump a Jacn file to XML format for viewing and debugging.
package bran.jacn.test; import bran.spring.jacn.AbstractJacnConfigFile; import bran.spring.jacn.ConvertUtil; import bran.spring.jacn.JacnApplicationContext; public class SimpleFlatJacnApp { private static final String HELLO = "hello"; public static void main(String[] args) throws Exception { System.out.println(ConvertUtil.jacn2Xml(Jacn_foo.class)); JacnApplicationContext ctx = new JacnApplicationContext (Jacn_foo.class); Foo foo = (Foo) ctx.getBean("foo"); if(HELLO.equals(foo.getBar().getMsg())) { System.out.println("good"); } else { System.out.println("bad"); } } static class Foo { Bar bar; public Bar getBar() {return bar;} public void setBar(Bar bar) {this.bar = bar;} } static class Bar { String msg; private Bar(String msg) {this.msg = msg;} public String getMsg() {return msg;} } /** * the configuration file */ static class Jacn_foo extends AbstractJacnConfigFile{ static Foo foo; static Bar bar; public void wire() throws Exception { bar = new Bar(HELLO); foo.setBar(bar); } } }
Play with it and get a good feel of the natural way of configuring DI.
There is another very useful tool in the ConvertUtil.java. By calling the xml2JacnClass() in the utility, as in
File f = new File("/path/myContext.xml"); String ss = ConvertUtil.xml2JacnClass(f); System.out.println(ss);
you'll realize that you immediately have got an almost valid Jacn configuration file! For heavily nested configurations you won't get everyting done for you automatically, but the skeleton code will get you started very quickly.
If you want to migrate a bunch of Spring XMLs, this is the tool to use. |
Here is a complete jacn configuration file.
package bran.jacn.test; import bran.spring.jacn.AbstractJacnConfigFile; public class ApplicationContext_foo extends AbstractJacnConfigFile{ static Foo foo; Foo foo1; Bar bar; public void wire() throws Exception { foo.setBar(bar); foo.setNum(1); foo.setCls(Foo.class); } }
The principles are:
Using Jacn with Spring is pretty much a drop-in replacement of the XML configurations. There are two runtime environment that Jacn can be used with Spring: in standalone Java applications and in web applications.
The above example shows how to use Jacn in a standalone application.
TODO:
The following table shows the capability of Jacn:
Topic | XML | Jacn |
---|---|---|
a simple singleton bean the static modifier is used to indicate the bean is a singleton |
<beans> <bean id="foo" class="Foo" /> </beans> |
class Jacnfig extends AbstractJacnConfigFile { static Foo foo; public void wire() throws Exception { } } |
prototype bean declare none static fields |
<beans> <bean id="foo" class="Foo" singleton="false"/> </beans> |
class Jacnfig extends AbstractJacnConfigFile { Foo foo; // instance field -> "prototype" bean public void wire() throws Exception { } } |
lazy init call lazyInit() method |
<beans> <bean id="foo" class="Foo" lazy-init="true"/> </beans> |
class Jacnfig extends AbstractJacnConfigFile { static Foo foo; public void wire() throws Exception { lazyInit(foo); } } |
property call the type-safe setters directly |
<beans> <bean id="foo" class="Foo"> <property name="bar"> <ref bean="bar"/> </property> </bean> <bean id="bar" class="Bar"/> </beans> |
class Jacnfig extends AbstractJacnConfigFile { static Foo foo; static Bar bar; public void wire() throws Exception { foo.setBar(bar); } } |
init method make a call to the method directly |
<beans> <bean id="foo" class="Foo" init-method="init" /> </beans> |
class Jacnfig extends AbstractJacnConfigFile { static Foo foo; public void wire() throws Exception { foo.init(); } } |
property place holder invoke the loadPlaceholderProperties() |
<beans> <bean id="propertyConfigurer" class="org.springframework...PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath:mail.properties</value> <value>classpath:database.properties</value> </list> </property> </bean> </beans> |
class Jacnfig extends AbstractJacnConfigFile { public void wire() throws Exception { loadPlaceholderProperties( new String[]{ "classpath:database.properties", "classpath:mail.properties"}); } } |
autowire invoke autoWireByName() or autoWireByType() |
<beans> <bean id="foo" class="Foo" autowire="byName"/> <bean id="foo2" class="Foo" autowire="byType"/> </beans> |
class Jacnfig extends AbstractJacnConfigFile { static Foo foo, foo2; public void wire() throws Exception { autoWireByName(foo); autoWireByType(foo2); } } |
use array new MyObject[]{...} |
<beans> <bean id="foo" class="Foo" > <property name="bars"> <list> <value>hello</value> <ref bean="b1"/> </list> </property> </bean> <bean id="b1" class="Bar" /> </beans> |
class Jacnfig extends AbstractJacnConfigFile { static Foo foo; static Bar b1; public void wire() throws Exception { foo.setBars(new Object[]{"hello", b1}); } } |
use List
|
<beans> <bean id="foo" class="Foo" > <property name="list"> <list> <value>hello</value> <ref bean="b1"/> </list> </property> </bean> <bean id="b1" class="Bar" /> </beans> |
class Jacnfig extends AbstractJacnConfigFile { static Foo foo; static Bar b1; public void wire() throws Exception { foo.setList(Arrays.asList(new Object[] {"hello", b1})); // or List l = new ArrayList(); { l.add("hello"); l.add(b1); } // I use curlies to pretty format the code foo.setList(l); // or Object l = new Object[]{"hello", b1}; foo.setList((List)l); // magic casting } } |
use Map create a Map and set it on the target |
<beans> <bean id="foo" class="Foo" > <property name="map"> <map> <entry key="config-map"> <value>MyConfigMap</value> </entry> <entry key="MailAccount"> <value>PopMailAccount</value> </entry> </map> </property> </bean> </beans> |
class Jacnfig extends AbstractJacnConfigFile { static Foo foo; public void wire() throws Exception { Map map = new Hashmap(); { map.put("config-map", "MyConfigMap"); map.put("MailAccount", "PopMailAccount"); } foo.setMap(map); } } |
use Properties create a Properties and set it on the target |
<beans> <bean id="foo" class="Foo" > <property name="props"> <property name="transactionAttributes"> <props> <prop key="*">PROPAGATION_REQUIRED</prop> </props> </property> </property> </bean> </beans> |
class Jacnfig extends AbstractJacnConfigFile { static Foo foo; public void wire() throws Exception { Properties p = new Proerpties(); { p.put("*", "PROPAGATION_REQUIRED"); } foo.setProps(p); } } |
reference external beans defined in XML Jacn and XML can co-exisit in an application. use refBean() to reference external beans |
<beans> <bean id="foo" class="Foo" > <property name="bar"> <ref bean="bar"/> </property> </bean> </beans> <beans> <bean id="bar" class="Bar" /> </beans> |
class Jacnfig extends AbstractJacnConfigFile { static Foo foo; public void wire() throws Exception { foo.setBar((Bar)refBean("bar")); } } <beans> <bean id="bar" class="Bar" /> </beans> |
reference external beans defined in another Jacn file just reference it as you would in Java |
<beans> <bean id="foo" class="Foo" /> <property name="bar"> <ref bean="bar"/> </property> </bean> </beans> <beans> <bean id="bar" class="Bar" /> </beans> |
class Jacnfig2 extends AbstractJacnConfigFile { static Foo foo; public void wire() throws Exception { foo.setBar(Jacnfig.bar); } } class Jacnfig extends AbstractJacnConfigFile { static Bar bar; public void wire() throws Exception { } } |
enable transactions on service objects enableTx(...) will do the trick |
<beans> <bean id="userManager" class="org...TransactionProxyFactoryBean"> <property name="transactionManager"> <ref local="transactionManager"/> </property> <property name="target"> <ref local="userManagerTarget"/> </property> <property name="transactionAttributes"> <props> <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop> <prop key="*">PROPAGATION_REQUIRED</prop> </props> </property> <property name="proxyInterfaces"> <value>IUserManager</value> </property> <property name="preInterceptors"> <list> <ref local="preInterceptor"/> </list> </property> <property name="postInterceptors"> <list> <ref local="postInterceptor"/> </list> </property> </bean> <bean id="userManagerTarget" class="UserManagerImpl"> <property name="userDao"> <ref bean="userDao"/> </property> </bean> </beans> |
class Jacnfig extends AbstractJacnConfigFile { static UserManagerImp userManager; //.. other dependents public void wire() throws Exception { Properties p = new Properties(); { p.put("get*", "PROPAGATION_REQUIRED,readOnly"); p.put("*", "PROPAGATION_REQUIRED"); } enableTx(userManager, transactionManager, p, new Class[]{IUserManager.class}, new Object[] {preInterceptor}, new Object[] {postInterceptor}); userManager.setUserDao(userDao); } } |
DI via contructors just make a call to the constructors as in Java |
<beans> <bean id="foo" class="Foo"> <constructor-arg> <ref bean="bar" /> </constructor-arg> <constructor-arg> <value>hello</value> </constructor-arg> </bean> </beans> |
class Jacnfig extends AbstractJacnConfigFile { static Foo foo; static Bar bar; public void wire() throws Exception { foo = new Foo(bar, "hello"); } } |
facory methods just make a call to the factory methods as in Java |
<beans> <bean id="a" class="bran.jacn.test.AA"> <property name="b2"> <bean class="bran.jacn.test.BBFactory" factory-method="newInstanceStatic"> <constructor-arg> <value>hello1</value> </constructor-arg> <constructor-arg> <value>b2</value> </constructor-arg> </bean> </property> </bean> </beans> |
static class Jacn_factoryMethod extends AbstractJacnConfigFile { static AA a; static BBeanFactory bbf; public void wire() throws Exception { a.setB1(bbf.newInstance("hello", "b1")); a.setB2(BBFactory.newInstanceStatic("hello1", "b2")); } } |
"init-method" and "destroy-method" make a init/destroy function call in the init()/destroy() method in the config file |
<beans> <bean id="des" class="bran.jacn.test.TestInitDestroyMethod$InitDestroyer" singleton="true" init-method="setup" destroy-method="clean" /> </beans> |
public static class Jacn_config extends AbstractJacnConfigFile { static InitDestroyer des; public void wire() throws Exception { } public void init() throws Exception { des.setup(); } public void destroy() throws Exception { des.clean(); } } |
TODO: