XDoclet是一款开源的代码自动生成引擎,支持很多框架的代码自动生成。
而XDoclet2作为Maven2的插件,支持Hibernate3的pojo->xml的代码自动生成。配合ant与Hibernate Tool API,可以实现pojo<->xml<->db schema的相互转化。具体关系为:
生成处理 |
实用工具 |
pojo->xml |
XDoclet2 |
xml->pojo
|
Hibernate Tool API |
pojo+xml -> db schema |
Hibernate Tool API |
db schema -> pojo+xml
|
可用myeclipse,本文不涉及 |
下面通过ANT脚本例子,来展示如何完成以上的转换。
1 <?xml version="1.0" encoding="utf-8"?>
2 <project name="xdoclet_example">
3
4 <!--xdoclet的jar包所在目录-->
5 <property name="xdoclet.plugin.install.dir" value="./lib/xdoclet" />
6 <!--待处理项目的src目录-->
7 <property name="src.dir" value="./src" />
8 <!--待处理项目的根目录-->
9 <property name="prj.dir" value="./" />
10
11 <!--include进来xdoclet所有jar包-->
12 <path id="xdoclet.task.classpath" description="xdoclet的所有jar">
13 <fileset dir="${xdoclet.plugin.install.dir}">
14 <include name="**/*.jar" />
15 </fileset>
16 </path>
17 <!--include进来待处理项目的所有jar包,意在使用hibernate相关的jar包-->
18 <path id="prj.jar" description="项目目录下的所有jar">
19 <fileset dir="${prj.dir}">
20 <include name="**/*.jar" />
21 </fileset>
22 </path>
23 <!--
24 继承上2个目录,同时需要把pojo编译好的class文件包含进来。
25 这里定义需要留意,很容易掉入到ant的bug陷阱里去。
26 详细可参照http://www.blogjava.net/boluobn/articles/136197.html
27 -->
28 <path id="runtime.path" description="SchemaExport用的jar和class文件">
29 <path refid="xdoclet.task.classpath" />
30 <path refid="prj.jar" />
31 <pathelement location="${prj.dir}/build/classes" />
32 </path>
33
34 <!--
35 xdoclet只在判断未存在hbm.xml的情况下才会生成,已存在的话则不会自动覆盖。
36 所以定义一个清空已存在的hbm.xml文件任务。
37 -->
38 <target name="clean" description="清空已有的hbm.xml">
39 <echo message="清空已有的hbm.xml" />
40 <delete dir="src">
41 <include name="**/po/*.hbm.xml" />
42 </delete>
43 </target>
44
45 <!--根据pojo生成hbm.xml,注意一下pojo的路径即可-->
46 <target name="xdoclet2hbm" description="根据pojo生成hbm.xml" depends="clean">
47 <echo message="根据pojo生成hbm.xml" />
48 <taskdef name="xdoclet" classname="org.xdoclet.ant.XDocletTask" classpathref="xdoclet.task.classpath" />
49 <xdoclet encoding="utf-8">
50 <fileset dir="${src.dir}">
51 <include name="**/po/*.java" />
52 </fileset>
53 <component classname="org.xdoclet.plugin.hibernate.HibernateMappingPlugin" destdir="${basedir}/${src.dir}" version="3.0" />
54 </xdoclet>
55 </target>
56
57 <!--根据hibernate.cfg.xml文件生成pojo-->
58 <target name="hbm2java" description="根据hbm.xml文件生成pojo">
59 <echo message="根据hbm.xml文件生成pojo" />
60 <taskdef name="hbm2java" classname="org.hibernate.tool.ant.HibernateToolTask" classpathref="runtime.path" />
61 <hbm2java destdir="${src.dir}">
62 <configuration configurationfile="${src.dir}/hibernate.cfg.xml" />
63 <hbm2java />
64 </hbm2java>
65 </target>
66
67 <!--
68 生成数据库环境的任务。
69 这个可能并不常用,使用org.hibernate.tool.hbm2ddl.SchemaExport编写一个JUnit test可以更方便的连搭环境带造数据。
70 -->
71 <target name="SchemaExport" description="根据hibernate.cfg.xml生成数据库环境">
72 <echo message="根据hibernate.cfg.xml生成数据库环境" />
73 <taskdef name="schemaexport" classname="org.hibernate.tool.hbm2ddl.SchemaExportTask" classpathref="runtime.path" />
74 <schemaexport config="${src.dir}/hibernate.cfg.xml" quiet="false" text="false" drop="false" delimiter=";" output="schema-export.sql" />
75 </target>
76
77 </project>
脚本很详细,看注释即可。
在使用xdoclet2hbm前,需要在pojo上设定javadoc注释,以告诉xdoclet如何进行解析。
one2one & one2many的例子:
Child.java
1 package po;
2
3 /**
4 * @hibernate.class table="child"
5 */
6 @SuppressWarnings("serial")
7 public class Child implements java.io.Serializable {
8
9 //xdoclet注释有写在getter上与写在field上2种方法。
10 //写在field上会自动生成access="field",所以写在getter上更常用一些。
11
12 private String id;
13 private String name;
14 private Father father;
15
16 /**
17 * @hibernate.id generator-class="uuid.hex" column="id" length="32"
18 */
19 public String getId() {
20 return this.id;
21 }
22
23 public void setId(String id) {
24 this.id = id;
25 }
26
27 //基本支持所有的hibernate 属性,所以想要啥设置就大胆的写吧
28 /**
29 * @hibernate.property column="name" length="32" not-null="true" type="java.lang.String" lazy="true"
30 */
31 public String getName() {
32 return this.name;
33 }
34
35 public void setName(String name) {
36 this.name = name;
37 }
38
39 /**
40 * @hibernate.many-to-one column="father_id" not-null="true"
41 */
42 public Father getFather() {
43 return this.father;
44 }
45
46 public void setFather(Father father) {
47 this.father = father;
48 }
49
50 }
Father.java
1 package po;
2
3 import java.util.HashSet;
4 import java.util.Set;
5
6 /**
7 * @hibernate.class table="father"
8 */
9 @SuppressWarnings("serial")
10 public class Father implements java.io.Serializable {
11
12 private String id;
13
14 private String name;
15
16 private Integer age;
17
18 private Set<Child> children = new HashSet<Child>(0);
19
20 /**
21 * @hibernate.id generator-class="uuid.hex" column="id" length="32"
22 */
23 public String getId() {
24 return this.id;
25 }
26
27 public void setId(String id) {
28 this.id = id;
29 }
30
31 /**
32 * @hibernate.property column="name" length="32" not-null="true" type="java.lang.String"
33 */
34 public String getName() {
35 return this.name;
36 }
37
38 public void setName(String name) {
39 this.name = name;
40 }
41
42 /**
43 * @hibernate.property column="age" length="32" type="java.lang.Integer"
44 */
45 public Integer getAge() {
46 return age;
47 }
48
49 public void setAge(Integer age) {
50 this.age = age;
51 }
52
53 /**
54 * @hibernate.set table="child"
55 * @hibernate.key column="father_id"
56 * @hibernate.one-to-many class="po.Child"
57 */
58 public Set<Child> getChildren() {
59 return children;
60 }
61
62 public void setChildren(Set<Child> children) {
63 this.children = children;
64 }
65 }
many2many的例子:
Student.java
1 package po;
2
3 import java.util.HashSet;
4 import java.util.Set;
5
6 /**
7 * @hibernate.class table="student"
8 */
9 @SuppressWarnings("serial")
10 public class Student implements java.io.Serializable {
11
12 private String id;
13 private String name;
14 private Set<Teacher> teachers = new HashSet<Teacher>(0);
15
16 /**
17 * @hibernate.id generator-class="uuid.hex" column="id" length="32"
18 */
19 public String getId() {
20 return this.id;
21 }
22
23 public void setId(String id) {
24 this.id = id;
25 }
26
27 /**
28 * @hibernate.property column="name" length="32" not-null="true" type="java.lang.String"
29 */
30 public String getName() {
31 return this.name;
32 }
33
34 public void setName(String name) {
35 this.name = name;
36 }
37
38 /**
39 * @hibernate.set table="student_teacher_relation"
40 * @hibernate.key column="student_id"
41 * @hibernate.many-to-many class="po.Teacher" column="teacher_id"
42 */
43 public Set<Teacher> getTeachers() {
44 return teachers;
45 }
46
47 public void setTeachers(Set<Teacher> teachers) {
48 this.teachers = teachers;
49 }
50 }
Teacher.java
1 package po;
2
3 import java.util.HashSet;
4 import java.util.Set;
5
6 /**
7 * @hibernate.class table="teacher"
8 */
9 @SuppressWarnings("serial")
10 public class Teacher implements java.io.Serializable {
11
12 private String id;
13 private String name;
14 private Set<Student> students = new HashSet<Student>(0);
15
16 /**
17 * @hibernate.id generator-class="uuid.hex" column="id" length="32"
18 */
19 public String getId() {
20 return this.id;
21 }
22
23 public void setId(String id) {
24 this.id = id;
25 }
26
27 /**
28 * @hibernate.property column="name" length="32" not-null="true" type="java.lang.String"
29 */
30 public String getName() {
31 return this.name;
32 }
33
34 public void setName(String name) {
35 this.name = name;
36 }
37
38 /**
39 * @hibernate.set table="student_teacher_relation"
40 * @hibernate.key column="teacher_id"
41 * @hibernate.many-to-many class="po.Student" column="student_id"
42 */
43 public Set<Student> getStudents() {
44 return students;
45 }
46
47 public void setStudents(Set<Student> students) {
48 this.students = students;
49 }
50
51 }
总结:
1.本文没有涉及hibernate annnotation模式,需要者请自行查阅相关资料。
2.XDoclet2没有XDoclet1代好找,推荐一个网址
Jar Search Engine
3.本文未能涉及在开发中,程序运转时遇到DB schema结构变化而进行的动态自动转换技术。如有高人知晓,请不吝赐教。