如果你并不打算使用类继承结构并不是很有必要阅读本文。
请先阅读我写的另一篇文章
"使用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.properties
4. 本文不再重复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.Payment
6.查错过程我就不说了,比较无聊,只说一下问题出在哪里
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); } } } }
本文地址:http://com.8s8s.com/it/it10331.htm