服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > J2EE > Servlet/Jsp > 查看文档

bug? hbm2javatask无法实现joined-subclass单独配置文件(2.1.2)


如果你并不打算使用类继承结构并不是很有必要阅读本文。请先阅读我写的另一篇文章 "使用hibernate扩展工具hbm2javatask根据配置文件生成持久化对象类(2.1.2)"1.在文档第8章(hibernate/doc/reference/zh-cn/html/inheritance.html)有提到

“每个子类一个表”的映射是这样的:

<class name="payment" table="payment"> <id name="id" type="long" column="payment_id"> <generator class="native"/> </id> <property name="amount" column="amount"/> ... <joined-subclass name="creditcardpayment" table="credit_payment"> <key column="payment_id"/> ... </joined-subclass> <joined-subclass name="cashpayment" table="cash_payment"> <key column="payment_id"/> ... </joined-subclass> <joined-subclass name="chequepayment" table="cheque_payment"> <key column="payment_id"/> ... </joined-subclass></class>

2.文档第5章(hibernate/doc/reference/zh-cn/html/mapping.html)有提到

允许在独立的映射文档中定义subclass和joined-subclass,直接位于hibernate-mapping下。这就可以让你每次扩展你的类层次的时候,加入新的映射文件就行了。在子类的映射中你必须指定一个extents属性,指明先前已经映射过的超类。使用这个功能的时候,一定要注意映射文件的排序是非常重要的!

<hibernate-mapping> <subclass name="eg.subclass.domesticcat" extends="eg.cat" discriminator-value="d"> <property name="name" type="string"/> </subclass></hibernate-mapping>
3.根据以上两点,偶根据第8章的payment创建了一个工程,把joined-subclass移了出来,现在工程目录结构如下 payment  <dir>|-src  <dir>|-hbm  <dir>  |-payment  <dir>    |-payment.hbm.xml    |-creditcardpayment.hbm.xml    |-cashpayment.hbm.xml|-classes  <dir>|-lib  <dir>|-build.xml|-hibernate.codegen.xml|-log4j.properties4. 本文不再重复build.xml, hibernate.codegen.xml, log4j.properties三个文件的内容。可在"使用hibernate扩展工具hbm2javatask根据配置文件生成持久化对象类(2.1.2)"一文查看这三个文件的内容。此处仅列出.hbm.xml文件内容。  4.1 payment.hbm.xml<?xml version="1.0" encoding="gbk"?><!doctype hibernate-mapping public "-//hibernate/hibernate mapping dtd//en" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"><hibernate-mapping>  <class name="payment.payment" table="payment">    <id name="id" type="long" column="payment_id">      <generator class="native"/>    </id>    <property name="amount" column="amount" type="long"/>  </class></hibernate-mapping>  4.2 creditcardpayment.hbm.xml
<?xml version="1.0" encoding="gbk"?><!doctype hibernate-mapping public "-//hibernate/hibernate mapping dtd//en" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"><hibernate-mapping><joined-subclass name="payment.creditcardpayment" table="credit_payment" extends="payment.payment"> <key column="payment_id"/></joined-subclass></hibernate-mapping>
  4.3 cashpayment.hbm.xml
<?xml version="1.0" encoding="gbk"?><!doctype hibernate-mapping public "-//hibernate/hibernate mapping dtd//en" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"><hibernate-mapping><joined-subclass name="payment.cashpayment" table="cash_payment" extends="payment.payment"> <key column="payment_id"/></joined-subclass></hibernate-mapping>
5.在命令行进入工程目录,运行ant,发生错误,关键提示如下: net.sf.hibernate.mappingexception: cannot extend unmapped class payment.payment6.查错过程我就不说了,比较无聊,只说一下问题出在哪里  6.1 hbm2javatask里对配置文件列表做了循环,每个文件单独处理,所以有关联的类就找不到了。   6.2 但是codegenerator类也有不妥,没有考虑文件排列问题,因为子类可能先于父类被处理。7.下面帖出两个修改过的文件代码。在修改的地方加了中文注释。  7.1 net.sf.hibernate.tool.hbm2java.hbm2javatask
package net.sf.hibernate.tool.hbm2java;import java.io.file;import java.io.printwriter;import java.io.stringwriter;import java.util.arraylist;import java.util.list;import org.apache.tools.ant.buildexception;import org.apache.tools.ant.directoryscanner;import org.apache.tools.ant.task;import org.apache.tools.ant.types.fileset;import org.apache.tools.ant.types.path;import org.apache.tools.ant.types.reference;import org.apache.commons.logging.log;import org.apache.commons.logging.logfactory;/** * task for hbm2java (hibernates codegenerator) * * * @author gbegley and max * */public class hbm2javatask extends task { private static final log log = logfactory.getlog(codegenerator.class); private file configurationfile; private path compileclasspath; private file outputdir; private list filesets = new arraylist(); /** * set a hbm2java <literal>config.xml</literal> configuration file * @param the file name */ public void setconfig(file configurationfile) { this.configurationfile = configurationfile; } /** * set the classpath to be used for this compilation. * * @param classpath an ant path object containing the compilation classpath. */ public void setclasspath(path classpath) { if (compileclasspath == null) { compileclasspath = classpath; } else { compileclasspath.append(classpath); } } /** gets the classpath to be used for this compilation. */ public path getclasspath() { return compileclasspath; } /** * adds a path to the classpath. */ public path createclasspath() { if (compileclasspath == null) { compileclasspath = new path(getproject()); } return compileclasspath.createpath(); } /** * adds a reference to a classpath defined elsewhere. */ public void setclasspathref(reference r) { createclasspath().setrefid(r); } /** * adds a set of files to translate. */ public void addfileset(fileset set) { filesets.add(set); } /** * sets the output directory. * * @param bindirectory directory */ public void setoutput(file outdirectory) { this.outputdir = outdirectory; } public void execute() throws buildexception { list filelist = gettargetfiles(); if (filelist.size() == 0) return; log("processing " + filelist.size() + " files."); try { log("building hibernate objects"); //这个循环是错误1, //for (int i = 0; i < filelist.size(); i++) { // processfile(outputdir, (file) filelist.get(i)); //} //要修改processfile方法 processfile(outputdir, filelist); } catch (throwable t) { stringwriter sw = new stringwriter(); t.printstacktrace(new printwriter(sw)); throw new buildexception("caused by:/n" + sw.tostring()); } } /** * * * comment: * the initial ant task had some initial filtering on the hbm.xml/java names to only process the needed files. * that is not possible to decide in the ant task without implementing the same logic present in hbm2java. * thus i've removed it and let it be something that hbm2java should do. * * * @return */ private list gettargetfiles() { list l = new java.util.arraylist(); // deal with the filesets for (int i = 0; i < filesets.size(); i++) { fileset fs = (fileset) filesets.get(i); file parent = fs.getdir( getproject() ); directoryscanner ds = fs.getdirectoryscanner(getproject()); string[] files = ds.getincludedfiles(); for (int j = 0; j < files.length; j++) { file srcfile = new file( parent, files[j] ); l.add( srcfile ); } } return l; } //修改了方法参数 private void processfile(file outputdir, list filelist) { list args = new arraylist(); if (outputdir != null) { args.add("--output=" + outputdir.getabsolutepath()); } if (configurationfile != null) { args.add("--config=" + configurationfile); } // 把所有文件都加入命令行参数 for ( int i = 0; i < filelist.size(); i++ ){ args.add(((file)filelist.get(i)).getabsolutepath()); } try { net.sf.hibernate.tool.hbm2java.codegenerator.main((string[]) args.toarray(new string[args.size()])); } catch (throwable t) { stringwriter sw = new stringwriter(); t.printstacktrace(new printwriter(sw)); throw new buildexception("caused by:/n" + sw.tostring()); } }}
  7.2 net.sf.hibernate.tool.hbm2java.codegenerator
/* * $id: codegenerator.java,v 1.7 2004/03/22 20:41:47 maxcsaucdk exp $ */package net.sf.hibernate.tool.hbm2java;import java.io.file;import java.util.arraylist;import java.util.hashmap;import java.util.iterator;import java.util.list;import net.sf.hibernate.mappingexception;import net.sf.hibernate.util.dtdentityresolver;import org.apache.commons.collections.multihashmap;import org.apache.commons.collections.multimap;import org.apache.commons.logging.log;import org.apache.commons.logging.logfactory;import org.jdom.document;import org.jdom.element;import org.jdom.input.saxbuilder;import org.xml.sax.errorhandler;import org.xml.sax.saxparseexception;/** * */public class codegenerator { private static final log log = logfactory.getlog(codegenerator.class); public static void main(string[] args) { if(args.length==0) { system.err.println("no arguments provided. nothing to do. exit."); system.exit(-1); } try { arraylist mappingfiles = new arraylist(); saxbuilder builder = new saxbuilder(true); builder.setentityresolver( new dtdentityresolver() ); builder.seterrorhandler( new errorhandler() { public void error(saxparseexception error) { log.error("error parsing xml: " + error.getsystemid() + '(' + error.getlinenumber() + ')',error); } public void fatalerror(saxparseexception error) { error(error); } public void warning(saxparseexception error) { log.warn("warning parsing xml: " + error.getsystemid() + '(' + error.getlinenumber() + ')' ); } } ); string outputdir = null; list generators = new arraylist(); multimap globalmetas = new multihashmap(); // parse command line parameters for (int i = 0; i < args.length; i++) { if (args[i].startswith("--")) { if ( args[i].startswith("--config=") ) { // parse config xml file builder.setvalidation(false); document document = builder.build( new file( args[i].substring(9) ) ); globalmetas = metaattributehelper.loadandmergemetamap(document.getrootelement(), null); iterator generateelements = document.getrootelement().getchildren("generate").iterator(); while (generateelements.hasnext()) { generators.add( new generator( (element) generateelements.next() ) ); } builder.setvalidation(true); } else if ( args[i].startswith("--output=") ) { outputdir = args[i].substring(9); } } else { mappingfiles.add( args[i] ); } } // if no config xml file, add a default generator if (generators.size() == 0) { generators.add( new generator() ); } hashmap classmappings = new hashmap(); builder.setvalidation(true); // 这个循环是错误2 // 改成只处理class映射 for ( iterator iter = mappingfiles.iterator(); iter.hasnext(); ) { // parse the mapping file file file = new file( (string) iter.next() ); log.debug(file.getabsolutepath()); document document = builder.build( file); element rootelement = document.getrootelement(); org.jdom.attribute a = rootelement.getattribute("package"); string pkg = null; if(a!=null) { pkg = a.getvalue(); } mappingelement me = new mappingelement(rootelement, null/**todo-hbm2java: - should be config.xml**/); iterator classelements = rootelement.getchildren("class").iterator(); multimap mm = metaattributehelper.loadandmergemetamap(rootelement, globalmetas); handleclass(pkg,me, classmappings, classelements, mm, false); } // 复制了上一个循环 // 处理subclass和joined-class映射 for ( iterator iter = mappingfiles.iterator(); iter.hasnext(); ) { // parse the mapping file file file = new file( (string) iter.next() ); document document = builder.build( file); element rootelement = document.getrootelement(); org.jdom.attribute a = rootelement.getattribute("package"); string pkg = null; if(a!=null) { pkg = a.getvalue(); } mappingelement me = new mappingelement(rootelement, null/**todo-hbm2java: - should be config.xml**/); multimap mm = metaattributehelper.loadandmergemetamap(rootelement, globalmetas); iterator classelements = rootelement.getchildren("subclass").iterator(); handleclass(pkg,me,classmappings, classelements, mm, true); classelements = rootelement.getchildren("joined-subclass").iterator(); handleclass(pkg,me,classmappings, classelements, mm, true); } // generate source files for ( iterator iterator = generators.iterator(); iterator.hasnext(); ) { generator g = (generator) iterator.next(); g.setbasedirname(outputdir); g.generate(classmappings); } } catch (exception e) { e.printstacktrace(); } } private static void handleclass(string classpackage, mappingelement me, hashmap classmappings, iterator classelements, multimap mm, boolean extendz) throws mappingexception { while ( classelements.hasnext() ) { element clazz = (element) classelements.next(); if(!extendz) { classmapping cmap = new classmapping(classpackage, clazz, me, mm); classmappings.put(cmap.getfullyqualifiedname(),cmap); } else { string ex = clazz.getattributevalue("extends"); if(ex==null) { throw new mappingexception("missing extends attribute on <" + clazz.getname() + " name=" + clazz.getattributevalue("name") + ">" ); } classmapping superclass = (classmapping) classmappings.get(ex); if(superclass == null) { throw new mappingexception("cannot extend unmapped class " + ex); } classmapping subclassmapping = new classmapping(classpackage, me, superclass.getclassname(), superclass, clazz, mm); superclass.addsubclass(subclassmapping); } } }}

扫描关注微信公众号