mybatis-generator生成报错The specified target project directory xxx does not exist及源码分析

mybatis-generator生成报错The specified target project directory xxx does not exist及源码分析

背景

参考macro大神的mall-learning项目搭建初始化框架的时候,在自己的项目里搭建了一个module来写代码,搭建generator代码的时候报错,The specified target project directory xxx does not exist
在这里插入图片描述
参考了一篇博客
mybatis逆向工程 The specified target project directory src\main\resources does not exist

然后加上模块名还是不对,还是报相同的错误

问题分析

这个报错的意思是指定的包不存在
百度了一下配置文件里targetProject的含义:

 targetProject:目标项目,指定一个存在的目录下,生成的内容会放到指定目录中,如果目录不存在,MBG不会自动建目录

但是文章中有句话给了我提示,targetProject是相对路径,为了搞清楚,我们看源码

实现类Generator

public class Generator {
    public static void main(String[] args) throws Exception {
        //MBG 执行过程中的警告信息
        List<String> warnings = new ArrayList<String>();
        //当生成的代码重复时,覆盖原代码
        boolean overwrite = true;
        //读取我们的 MBG 配置文件
        InputStream is = Generator.class.getResourceAsStream("/generatorConfig.xml");
        ConfigurationParser cp = new ConfigurationParser(warnings);
        Configuration config = cp.parseConfiguration(is);
        is.close();

        DefaultShellCallback callback = new DefaultShellCallback(overwrite);
        //创建 MBG
        MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
        //执行生成代码
        myBatisGenerator.generate(null);
        //输出警告信息
        for (String warning : warnings) {
            System.out.println(warning);
        }
    }
}

异常是myBatisGenerator.generate(null);这句产生的,往下找

    /**
     * This is the main method for generating code. This method is long running, but progress can be provided and the
     * method can be cancelled through the ProgressCallback interface.
     *
     * @param callback
     *            an instance of the ProgressCallback interface, or <code>null</code> if you do not require progress
     *            information
     * @param contextIds
     *            a set of Strings containing context ids to run. Only the contexts with an id specified in this list
     *            will be run. If the list is null or empty, than all contexts are run.
     * @param fullyQualifiedTableNames
     *            a set of table names to generate. The elements of the set must be Strings that exactly match what's
     *            specified in the configuration. For example, if table name = "foo" and schema = "bar", then the fully
     *            qualified table name is "foo.bar". If the Set is null or empty, then all tables in the configuration
     *            will be used for code generation.
     * @param writeFiles
     *            if true, then the generated files will be written to disk.  If false,
     *            then the generator runs but nothing is written
     * @throws SQLException
     *             the SQL exception
     * @throws IOException
     *             Signals that an I/O exception has occurred.
     * @throws InterruptedException
     *             if the method is canceled through the ProgressCallback
     */
    public void generate(ProgressCallback callback, Set<String> contextIds,
            Set<String> fullyQualifiedTableNames, boolean writeFiles) throws SQLException,
            IOException, InterruptedException {

        if (callback == null) {
            callback = new NullProgressCallback();
        }

        generatedJavaFiles.clear();
        generatedXmlFiles.clear();

        // calculate the contexts to run
        List<Context> contextsToRun;
        if (contextIds == null || contextIds.size() == 0) {
            contextsToRun = configuration.getContexts();
        } else {
            contextsToRun = new ArrayList<Context>();
            for (Context context : configuration.getContexts()) {
                if (contextIds.contains(context.getId())) {
                    contextsToRun.add(context);
                }
            }
        }

        // setup custom classloader if required
        if (configuration.getClassPathEntries().size() > 0) {
            ClassLoader classLoader = getCustomClassloader(configuration.getClassPathEntries());
            ObjectFactory.addExternalClassLoader(classLoader);
        }

        // now run the introspections...
        int totalSteps = 0;
        for (Context context : contextsToRun) {
            totalSteps += context.getIntrospectionSteps();
        }
        callback.introspectionStarted(totalSteps);

        for (Context context : contextsToRun) {
            context.introspectTables(callback, warnings,
                    fullyQualifiedTableNames);
        }

        // now run the generates
        totalSteps = 0;
        for (Context context : contextsToRun) {
            totalSteps += context.getGenerationSteps();
        }
        callback.generationStarted(totalSteps);

        for (Context context : contextsToRun) {
            context.generateFiles(callback, generatedJavaFiles,
                    generatedXmlFiles, warnings);
        }

        // now save the files
        if (writeFiles) {
            callback.saveStarted(generatedXmlFiles.size()
                + generatedJavaFiles.size());

            for (GeneratedXmlFile gxf : generatedXmlFiles) {
                projects.add(gxf.getTargetProject());
                writeGeneratedXmlFile(gxf, callback);
            }

            for (GeneratedJavaFile gjf : generatedJavaFiles) {
                projects.add(gjf.getTargetProject());
                writeGeneratedJavaFile(gjf, callback);
            }

            for (String project : projects) {
                shellCallback.refreshProject(project);
            }
        }

        callback.done();
    }

打断点发现主要是这里使用了配置文件里的target

        for (GeneratedJavaFile gjf : generatedJavaFiles) {
                projects.add(gjf.getTargetProject());
                writeGeneratedJavaFile(gjf, callback);
            }

我们进去查看这个方法的实现

private void writeGeneratedJavaFile(GeneratedJavaFile gjf, ProgressCallback callback)
           throws InterruptedException, IOException {
       File targetFile;
       String source;
       try {
           File directory = shellCallback.getDirectory(gjf
                   .getTargetProject(), gjf.getTargetPackage());
           targetFile = new File(directory, gjf.getFileName());
           if (targetFile.exists()) {
               if (shellCallback.isMergeSupported()) {
                   source = shellCallback.mergeJavaFile(gjf
                           .getFormattedContent(), targetFile
                           .getAbsolutePath(),
                           MergeConstants.OLD_ELEMENT_TAGS,
                           gjf.getFileEncoding());
               } else if (shellCallback.isOverwriteEnabled()) {
                   source = gjf.getFormattedContent();
                   warnings.add(getString("Warning.11", //$NON-NLS-1$
                           targetFile.getAbsolutePath()));
               } else {
                   source = gjf.getFormattedContent();
                   targetFile = getUniqueFileName(directory, gjf
                           .getFileName());
                   warnings.add(getString(
                           "Warning.2", targetFile.getAbsolutePath())); //$NON-NLS-1$
               }
           } else {
               source = gjf.getFormattedContent();
           }

           callback.checkCancel();
           callback.startTask(getString(
                   "Progress.15", targetFile.getName())); //$NON-NLS-1$
           writeFile(targetFile, source, gjf.getFileEncoding());
       } catch (ShellException e) {
           warnings.add(e.getMessage());
       }
   }

断点发现主要是File directory = shellCallback.getDirectory(gjf .getTargetProject(), gjf.getTargetPackage());抛出的异常

我们继续往里面看

public File getDirectory(String targetProject, String targetPackage)
            throws ShellException {
        // targetProject is interpreted as a directory that must exist
        //
        // targetPackage is interpreted as a sub directory, but in package
        // format (with dots instead of slashes). The sub directory will be
        // created
        // if it does not already exist

        File project = new File(targetProject);
        if (!project.isDirectory()) {
            throw new ShellException(getString("Warning.9", //$NON-NLS-1$
                    targetProject));
        }

        StringBuilder sb = new StringBuilder();
        StringTokenizer st = new StringTokenizer(targetPackage, "."); //$NON-NLS-1$
        while (st.hasMoreTokens()) {
            sb.append(st.nextToken());
            sb.append(File.separatorChar);
        }

        File directory = new File(project, sb.toString());
        if (!directory.isDirectory()) {
            boolean rc = directory.mkdirs();
            if (!rc) {
                throw new ShellException(getString("Warning.10", //$NON-NLS-1$
                        directory.getAbsolutePath()));
            }
        }

        return directory;
    }

这里发现,我们generatorConfig.xmltargetProject主要是在这个方法里生成File对象
又因为File创建可以根据绝对路径,也可以根据相对路径,当我们在generatorConfig.xml配置相对路径的时候,File对象会以项目路径(即user.dir目录)去寻找这个FILE对象,由于相对路径不对,找不到对应的文件夹,project.isDirectory()就为false,就会爆出The specified target project directory xxx does not exist的异常,也因为这个问题,我们就能理解这句话targetProject:目标项目,指定一个存在的目录下,生成的内容会放到指定目录中,如果目录不存在,MBG不会自动建目录的意义,当文件夹不存在的时候,他会抛出异常,而不会创建相关文件

解决方法

  • 使用绝对路径
  • 使用相对路径的时候找准相对路径
    • 介绍一个简单的找相对路径方法,idea左侧目录找到你的module,右键,copy relative path就可以得到这个module相对于usr.dir的相对路径,如(module-one),然后拼接原来的src/main/java,组成module-one/src/main/java即可
      在这里插入图片描述

参考文章

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值