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)有提到

允许在独立的映射文档中定义subclassjoined-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);
            }
        }
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值