• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mybatis / generator / 2213

14 May 2026 03:10PM UTC coverage: 91.803% (-0.04%) from 91.84%
2213

push

github

web-flow
Merge pull request #1514 from jeffgbutler/additive-merger

Allow Configuration for the Java Merger

2519 of 3223 branches covered (78.16%)

311 of 325 new or added lines in 24 files covered. (95.69%)

11 existing lines in 4 files now uncovered.

12208 of 13298 relevant lines covered (91.8%)

0.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

60.38
/core/mybatis-generator-core/src/main/java/org/mybatis/generator/api/MyBatisGenerator.java
1
/*
2
 *    Copyright 2006-2026 the original author or authors.
3
 *
4
 *    Licensed under the Apache License, Version 2.0 (the "License");
5
 *    you may not use this file except in compliance with the License.
6
 *    You may obtain a copy of the License at
7
 *
8
 *       https://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 *    Unless required by applicable law or agreed to in writing, software
11
 *    distributed under the License is distributed on an "AS IS" BASIS,
12
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 *    See the License for the specific language governing permissions and
14
 *    limitations under the License.
15
 */
16
package org.mybatis.generator.api;
17

18
import static org.mybatis.generator.internal.util.ClassloaderUtility.getCustomClassloader;
19
import static org.mybatis.generator.internal.util.StringUtility.mapStringValueOrElseGet;
20
import static org.mybatis.generator.internal.util.messages.Messages.getString;
21

22
import java.io.BufferedWriter;
23
import java.io.File;
24
import java.io.IOException;
25
import java.io.OutputStream;
26
import java.io.OutputStreamWriter;
27
import java.nio.charset.Charset;
28
import java.nio.file.Files;
29
import java.nio.file.Path;
30
import java.nio.file.StandardOpenOption;
31
import java.sql.SQLException;
32
import java.util.ArrayList;
33
import java.util.Collection;
34
import java.util.HashSet;
35
import java.util.List;
36
import java.util.Objects;
37
import java.util.Set;
38

39
import org.jspecify.annotations.Nullable;
40
import org.mybatis.generator.codegen.CalculatedContextValues;
41
import org.mybatis.generator.codegen.GenerationEngine;
42
import org.mybatis.generator.codegen.GenerationResults;
43
import org.mybatis.generator.codegen.IntrospectionEngine;
44
import org.mybatis.generator.codegen.RootClassInfo;
45
import org.mybatis.generator.config.Configuration;
46
import org.mybatis.generator.config.Context;
47
import org.mybatis.generator.config.IndentationConfiguration;
48
import org.mybatis.generator.config.JavaMergeConfiguration;
49
import org.mybatis.generator.exception.InternalException;
50
import org.mybatis.generator.exception.InvalidConfigurationException;
51
import org.mybatis.generator.exception.MergeException;
52
import org.mybatis.generator.exception.ShellException;
53
import org.mybatis.generator.internal.DefaultShellCallback;
54
import org.mybatis.generator.internal.ObjectFactory;
55
import org.mybatis.generator.merge.java.JavaFileMerger;
56
import org.mybatis.generator.merge.java.JavaMergerFactory;
57
import org.mybatis.generator.merge.xml.XmlFileMergerJaxp;
58

59
/**
60
 * This class is the main interface to MyBatis generator. A typical execution of the tool involves these steps:
61
 * <ol>
62
 * <li>Create a Configuration object. The Configuration can be the result of a parsing the XML configuration file, or it
63
 * can be created solely in Java.</li>
64
 * <li>Create a MyBatisGenerator object</li>
65
 * <li>Call one of the generate() methods</li>
66
 * </ol>
67
 *
68
 * @author Jeff Butler
69
 *
70
 * @see org.mybatis.generator.config.xml.ConfigurationParser
71
 */
72
public class MyBatisGenerator {
73
    private final Configuration configuration;
74
    private final ShellCallback shellCallback;
75
    private final ProgressCallback progressCallback;
76
    private final Set<String> contextIds;
77
    private final Set<String> fullyQualifiedTableNames;
78
    private final JavaFileMerger javaFileMerger;
79
    private final boolean isOverwriteEnabled;
80
    private final boolean isJavaFileMergeEnabled;
81
    private final Indenter indenter;
82

83
    private final List<GenerationResults> generationResultsList = new ArrayList<>();
1✔
84

85
    private MyBatisGenerator(Builder builder) {
1✔
86
        configuration = Objects.requireNonNull(builder.configuration, getString("RuntimeError.2")); //$NON-NLS-1$
1✔
87
        shellCallback = Objects.requireNonNullElseGet(builder.shellCallback, DefaultShellCallback::new);
1✔
88
        progressCallback = Objects.requireNonNullElseGet(builder.progressCallback, () -> new ProgressCallback() {});
1✔
89
        fullyQualifiedTableNames = builder.fullyQualifiedTableNames;
1✔
90
        contextIds = builder.contextIds;
1✔
91
        indenter = configuration.getIndentationConfiguration()
1✔
92
                .map(IndentationConfiguration::getIndenter)
1✔
93
                .orElseGet(() -> Objects.requireNonNullElseGet(builder.indenter, Indenter::defaultIndenter));
1✔
94

95
        if (builder.isJavaFileMergeEnabled) {
1!
96
            isJavaFileMergeEnabled = true;
×
NEW
97
            JavaMergeConfiguration javaMergeConfiguration = configuration.getJavaMergeConfiguration()
×
NEW
98
                    .orElseGet(JavaMergeConfiguration::defaultMergeConfiguration);
×
NEW
99
            javaFileMerger = JavaMergerFactory.getMerger(javaMergeConfiguration, indenter);
×
UNCOV
100
        } else {
×
101
            isJavaFileMergeEnabled = false;
1✔
102
            javaFileMerger = (newContent, existingContent) -> newContent;
1✔
103
        }
104

105
        isOverwriteEnabled = builder.isOverwriteEnabled;
1✔
106
    }
1✔
107

108
    /**
109
     * This is one of the main methods for generating code. This method is long-running, but progress can be provided
110
     * and the method can be canceled through the ProgressCallback interface. This method will not write results to
111
     * the disk. The generated objects can be retrieved from the getGeneratedJavaFiles(), getGeneratedKotlinFiles(),
112
     * getGeneratedXmlFiles(), and getGeneratedGenericFiles() methods.
113
     *
114
     * @return any warnings created during the generation process
115
     * @throws SQLException
116
     *             the SQL exception
117
     * @throws InterruptedException
118
     *             if the method is canceled through the ProgressCallback
119
     * @throws InvalidConfigurationException
120
     *             if the specified configuration is invalid
121
     */
122
    public List<String> generateOnly() throws SQLException, InterruptedException,
123
            InvalidConfigurationException {
124
        List<String> warnings = new ArrayList<>();
1✔
125
        generateFiles(warnings);
1✔
126
        progressCallback.done();
1✔
127
        return warnings;
1✔
128
    }
129

130
    /**
131
     * This is one of the main methods for generating code. This method is long-running, but progress can be provided
132
     * and the method can be canceled through the ProgressCallback interface. This method will write results to
133
     * the disk.
134
     *
135
     * @return any warnings created during the generation process
136
     * @throws SQLException
137
     *             the SQL exception
138
     * @throws IOException
139
     *             Signals that an I/O exception has occurred.
140
     * @throws InterruptedException
141
     *             if the method is canceled through the ProgressCallback
142
     * @throws InvalidConfigurationException
143
     *             if the specified configuration is invalid
144
     */
145
    public List<String> generateAndWrite() throws SQLException, IOException, InterruptedException,
146
            InvalidConfigurationException {
147
        List<String> warnings = new ArrayList<>();
1✔
148
        generateFiles(warnings);
1✔
149
        writeGeneratedFiles(warnings);
1✔
150
        progressCallback.done();
1✔
151
        return warnings;
1✔
152
    }
153

154
    private void generateFiles(List<String> warnings) throws SQLException, InterruptedException,
155
            InvalidConfigurationException {
156
        configuration.validate();
1✔
157
        generationResultsList.clear();
1✔
158
        ObjectFactory.reset();
1✔
159
        RootClassInfo.reset();
1✔
160

161
        setupCustomClassloader();
1✔
162
        List<Context> contextsToRun = calculateContextsToRun();
1✔
163
        List<CalculatedContextValues> contextValuesList = calculateContextValues(contextsToRun, indenter,
1✔
164
                warnings);
165
        List<ContextValuesAndTables> contextValuesAndTablesList = runAllIntrospections(contextValuesList, warnings);
1✔
166
        List<GenerationEngine> generationEngines = createGenerationEngines(contextValuesAndTablesList, warnings);
1✔
167
        runGenerationEngines(generationEngines);
1✔
168
    }
1✔
169

170
    private void setupCustomClassloader() {
171
        if (!configuration.getClassPathEntries().isEmpty()) {
1!
172
            ClassLoader classLoader = getCustomClassloader(configuration.getClassPathEntries());
×
173
            ObjectFactory.addExternalClassLoader(classLoader);
×
174
        }
175
    }
1✔
176

177
    private List<Context> calculateContextsToRun() {
178
        List<Context> contextsToRun;
179
        if (fullyQualifiedTableNames.isEmpty()) {
1!
180
            contextsToRun = configuration.getContexts();
1✔
181
        } else {
182
            contextsToRun = configuration.getContexts().stream()
×
183
                    .filter(c -> contextIds.contains(c.getId()))
×
184
                    .toList();
×
185
        }
186

187
        return contextsToRun;
1✔
188
    }
189

190
    private List<CalculatedContextValues> calculateContextValues(List<Context> contextsToRun, Indenter indenter,
191
                                                                 List<String> warnings) {
192
        return contextsToRun.stream()
1✔
193
                .map(c -> createContextValues(c, indenter, warnings))
1✔
194
                .toList();
1✔
195
    }
196

197
    private CalculatedContextValues createContextValues(Context context, Indenter indenter,
198
                                                        List<String> warnings) {
199
        return new CalculatedContextValues.Builder()
1✔
200
                .withContext(context)
1✔
201
                .withWarnings(warnings)
1✔
202
                .withIndenter(indenter)
1✔
203
                .build();
1✔
204
    }
205

206
    private List<ContextValuesAndTables> runAllIntrospections(List<CalculatedContextValues> contextValuesList,
207
                                                              List<String> warnings)
208
            throws SQLException, InterruptedException {
209
        int totalSteps = contextValuesList.stream()
1✔
210
                .map(CalculatedContextValues::context)
1✔
211
                .mapToInt(Context::getIntrospectionSteps)
1✔
212
                .sum();
1✔
213
        progressCallback.introspectionStarted(totalSteps);
1✔
214

215
        List<ContextValuesAndTables> contextValuesAndTablesList = new ArrayList<>();
1✔
216
        for (CalculatedContextValues contextValues : contextValuesList) {
1✔
217
            contextValuesAndTablesList.add(new ContextValuesAndTables(contextValues,
1✔
218
                    runContextIntrospection(fullyQualifiedTableNames, contextValues, warnings)));
1✔
219
        }
1✔
220

221
        return contextValuesAndTablesList;
1✔
222
    }
223

224
    private List<IntrospectedTable> runContextIntrospection(Set<String> fullyQualifiedTableNames,
225
                                                            CalculatedContextValues contextValues,
226
                                                            List<String> warnings)
227
            throws SQLException, InterruptedException {
228
        List<IntrospectedTable> answer = new IntrospectionEngine.Builder()
1✔
229
                .withContextValues(contextValues)
1✔
230
                .withFullyQualifiedTableNames(fullyQualifiedTableNames)
1✔
231
                .withWarnings(warnings)
1✔
232
                .withProgressCallback(progressCallback)
1✔
233
                .build()
1✔
234
                .introspectTables();
1✔
235

236
        answer.forEach(t -> contextValues.pluginAggregator().initialized(t));
1✔
237

238
        return answer;
1✔
239
    }
240

241
    private List<GenerationEngine> createGenerationEngines(List<ContextValuesAndTables> contextValuesAndTablesListList,
242
                                                           List<String> warnings) {
243
        return contextValuesAndTablesListList.stream()
1✔
244
                .map(c -> createGenerationEngine(c, warnings))
1✔
245
                .toList();
1✔
246
    }
247

248
    private GenerationEngine createGenerationEngine(ContextValuesAndTables contextValuesAndTables,
249
                                                    List<String> warnings) {
250
        return new GenerationEngine.Builder()
1✔
251
                .withContextValues(contextValuesAndTables.contextValues())
1✔
252
                .withProgressCallback(progressCallback)
1✔
253
                .withWarnings(warnings)
1✔
254
                .withIntrospectedTables(contextValuesAndTables.introspectedTables())
1✔
255
                .build();
1✔
256
    }
257

258
    private void runGenerationEngines(List<GenerationEngine> generationEngines) throws InterruptedException {
259
        // calculate the number of steps
260
        int totalSteps = generationEngines.stream().mapToInt(GenerationEngine::getGenerationSteps).sum();
1✔
261
        progressCallback.generationStarted(totalSteps);
1✔
262

263
        // now run the generators
264
        for (GenerationEngine generationEngine: generationEngines) {
1✔
265
            var generationResults = generationEngine.generate();
1✔
266
            generationResultsList.add(generationResults);
1✔
267
        }
1✔
268
    }
1✔
269

270
    private void writeGeneratedFiles(List<String> warnings) throws IOException, InterruptedException {
271
        Set<String> projects = new HashSet<>();
1✔
272
        int totalSteps = generationResultsList.stream().mapToInt(GenerationResults::getNumberOfGeneratedFiles).sum();
1✔
273
        progressCallback.saveStarted(totalSteps);
1✔
274

275
        for (GenerationResults generationResults : generationResultsList) {
1✔
276
            for (GeneratedXmlFile gxf : generationResults.generatedXmlFiles()) {
1!
277
                projects.add(gxf.getTargetProject());
×
278
                writeGeneratedXmlFile(gxf, generationResults.xmlFormatter(), warnings);
×
279
            }
×
280

281
            for (GeneratedJavaFile gjf : generationResults.generatedJavaFiles()) {
1!
282
                projects.add(gjf.getTargetProject());
×
283
                writeGeneratedJavaFile(gjf, generationResults.javaFormatter(), generationResults.javaFileEncoding(),
×
284
                        warnings);
285
            }
×
286

287
            for (GeneratedKotlinFile gkf : generationResults.generatedKotlinFiles()) {
1!
288
                projects.add(gkf.getTargetProject());
×
289
                writeGeneratedKotlinFile(gkf, generationResults.kotlinFormatter(),
×
290
                        generationResults.kotlinFileEncoding(), warnings);
×
291
            }
×
292

293
            for (GenericGeneratedFile gf : generationResults.generatedGenericFiles()) {
1!
294
                projects.add(gf.getTargetProject());
×
295
                writeGenericGeneratedFile(gf, warnings);
×
296
            }
×
297
        }
1✔
298

299
        for (String project : projects) {
1!
300
            shellCallback.refreshProject(project);
×
301
        }
×
302
    }
1✔
303

304
    private void writeGeneratedJavaFile(GeneratedJavaFile gf, JavaFormatter javaFormatter,
305
                                        @Nullable String javaFileEncoding, List<String> warnings)
306
            throws InterruptedException, IOException {
307
        String source = javaFormatter.getFormattedContent(gf.getCompilationUnit());
×
308
        writeFile(source, javaFileEncoding, gf, warnings, isJavaFileMergeEnabled,
×
309
                (newContent, existingContent) -> javaFileMerger.getMergedSource(newContent, existingContent,
×
310
                        javaFileEncoding));
311
    }
×
312

313
    private void writeGeneratedKotlinFile(GeneratedKotlinFile gf, KotlinFormatter kotlinFormatter,
314
                                          @Nullable String kotlinFileEncoding, List<String> warnings)
315
            throws InterruptedException, IOException {
316
        String source = kotlinFormatter.getFormattedContent(gf.getKotlinFile());
×
317
        writeFile(source, kotlinFileEncoding, gf, warnings, false, Merger.noMerge());
×
318
    }
×
319

320
    private void writeGenericGeneratedFile(GenericGeneratedFile gf, List<String> warnings)
321
            throws InterruptedException, IOException {
322
        String source = gf.getFormattedContent();
×
323
        writeFile(source, gf.getFileEncoding().orElse(null), gf, warnings, false, Merger.noMerge());
×
324
    }
×
325

326
    private void writeGeneratedXmlFile(GeneratedXmlFile gf, XmlFormatter xmlFormatter, List<String> warnings)
327
            throws InterruptedException, IOException {
328
        String source = xmlFormatter.getFormattedContent(gf.getDocument());
×
329
        writeFile(source, "UTF-8", gf, warnings, true, XmlFileMergerJaxp::getMergedSource); //$NON-NLS-1$
×
330
    }
×
331

332
    private void writeFile(String content, @Nullable String encoding, GeneratedFile gf, List<String> warnings,
333
                           boolean mergeEnabled, Merger merger)
334
            throws InterruptedException, IOException {
335
        try {
336
            File directory = shellCallback.getDirectory(gf.getTargetProject(), gf.getTargetPackage());
×
337
            Path targetFile = directory.toPath().resolve(gf.getFileName());
×
338
            if (Files.exists(targetFile)) {
×
339
                if (mergeEnabled && gf.isMergeable()) {
×
340
                    content = merger.apply(content, targetFile.toFile());
×
341
                } else if (isOverwriteEnabled) {
×
342
                    warnings.add(getString("Warning.11", targetFile.toFile().getAbsolutePath())); //$NON-NLS-1$
×
343
                } else {
344
                    targetFile = getUniqueFileName(directory, gf.getFileName());
×
345
                    warnings.add(getString("Warning.2", targetFile.toFile().getAbsolutePath())); //$NON-NLS-1$
×
346
                }
347
            }
348

349
            progressCallback.checkCancel();
×
350
            progressCallback.startTask(getString("Progress.15", targetFile.toString())); //$NON-NLS-1$
×
351
            writeFile(targetFile.toFile(), content, encoding);
×
352
        } catch (ShellException e) {
×
353
            warnings.add(e.getMessage());
×
354
        } catch (MergeException e) {
×
355
            warnings.add(e.getMessage());
×
356
            warnings.addAll(e.getExtraMessages());
×
357
        }
×
358
    }
×
359

360
    /**
361
     * Writes, or overwrites, the contents of the specified file.
362
     *
363
     * @param file
364
     *            the file
365
     * @param content
366
     *            the content
367
     * @param fileEncoding
368
     *            the file encoding
369
     * @throws IOException
370
     *             Signals that an I/O exception has occurred.
371
     */
372
    private void writeFile(File file, String content, @Nullable String fileEncoding) throws IOException {
373
        Charset cs = mapStringValueOrElseGet(fileEncoding, Charset::forName, Charset::defaultCharset);
×
374
        try (OutputStream outputStream = Files.newOutputStream(file.toPath(), StandardOpenOption.CREATE,
×
375
                StandardOpenOption.TRUNCATE_EXISTING)) {
376
            try (OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream, cs)) {
×
377
                try (BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter)) {
×
378
                    bufferedWriter.write(content);
×
379
                }
380
            }
381
        }
382
    }
×
383

384
    /**
385
     * Gets the unique file name.
386
     *
387
     * @param directory
388
     *            the directory
389
     * @param fileName
390
     *            the file name
391
     * @return the unique file name
392
     */
393
    private Path getUniqueFileName(File directory, String fileName) {
394
        Path answer = null;
×
395

396
        // try up to 1000 times to generate a unique file name
397
        StringBuilder sb = new StringBuilder();
×
398
        for (int i = 1; i < 1000; i++) {
×
399
            sb.setLength(0);
×
400
            sb.append(fileName);
×
401
            sb.append('.');
×
402
            sb.append(i);
×
403

404
            Path testFile = directory.toPath().resolve(sb.toString());
×
405
            if (Files.notExists(testFile)) {
×
406
                answer = testFile;
×
407
                break;
×
408
            }
409
        }
410

411
        if (answer == null) {
×
412
            throw new InternalException(getString("RuntimeError.3", directory.getAbsolutePath())); //$NON-NLS-1$
×
413
        }
414

415
        return answer;
×
416
    }
417

418
    /**
419
     * Returns the list of generated Java files after a call to one of the generate methods.
420
     * This is useful if you prefer to process the generated files yourself and do not want
421
     * the generator to write them to disk.
422
     *
423
     * @return the list of generated Java files
424
     */
425
    public List<GeneratedJavaFile> getGeneratedJavaFiles() {
426
        return generationResultsList.stream()
1✔
427
                .map(GenerationResults::generatedJavaFiles)
1✔
428
                .flatMap(Collection::stream)
1✔
429
                .toList();
1✔
430
    }
431

432
    /**
433
     * Returns the list of generated Kotlin files after a call to one of the generate methods.
434
     * This is useful if you prefer to process the generated files yourself and do not want
435
     * the generator to write them to disk.
436
     *
437
     * @return the list of generated Kotlin files
438
     */
439
    public List<GeneratedKotlinFile> getGeneratedKotlinFiles() {
440
        return generationResultsList.stream()
1✔
441
                .map(GenerationResults::generatedKotlinFiles)
1✔
442
                .flatMap(Collection::stream)
1✔
443
                .toList();
1✔
444
    }
445

446
    /**
447
     * Returns the list of generated XML files after a call to one of the generate methods.
448
     * This is useful if you prefer to process the generated files yourself and do not want
449
     * the generator to write them to disk.
450
     *
451
     * @return the list of generated XML files
452
     */
453
    public List<GeneratedXmlFile> getGeneratedXmlFiles() {
454
        return generationResultsList.stream()
1✔
455
                .map(GenerationResults::generatedXmlFiles)
1✔
456
                .flatMap(Collection::stream)
1✔
457
                .toList();
1✔
458
    }
459

460
    /**
461
     * Returns the list of generated generic files after a call to one of the generate methods.
462
     * This is useful if you prefer to process the generated files yourself and do not want
463
     * the generator to write them to disk.
464
     *
465
     * <p>The list will be empty unless you have used a plugin that generates generic files
466
     * or are using a custom runtime.
467
     *
468
     * @return the list of generated generic files
469
     */
470
    public List<GenericGeneratedFile> getGeneratedGenericFiles() {
471
        return generationResultsList.stream()
×
472
                .map(GenerationResults::generatedGenericFiles)
×
473
                .flatMap(Collection::stream)
×
474
                .toList();
×
475
    }
476

477
    private record ContextValuesAndTables(CalculatedContextValues contextValues,
1✔
478
                                          List<IntrospectedTable> introspectedTables) { }
479

480
    @FunctionalInterface
481
    private interface Merger {
482
        String apply(String newContent, File existingContent) throws MergeException;
483

484
        static Merger noMerge() {
485
            return (newContent, existingContent) -> newContent;
×
486
        }
487
    }
488

489
    public static class Builder {
1✔
490
        private @Nullable Configuration configuration;
491
        private @Nullable ShellCallback shellCallback;
492
        private @Nullable ProgressCallback progressCallback;
493
        private final Set<String> contextIds = new HashSet<>();
1✔
494
        private final Set<String> fullyQualifiedTableNames = new HashSet<>();
1✔
495
        private boolean isOverwriteEnabled = false;
1✔
496
        private boolean isJavaFileMergeEnabled = false;
1✔
497
        private @Nullable Indenter indenter;
498

499
        public Builder withConfiguration(Configuration configuration) {
500
            this.configuration = configuration;
1✔
501
            return this;
1✔
502
        }
503

504
        public Builder withShellCallback(ShellCallback shellCallback) {
505
            this.shellCallback = shellCallback;
1✔
506
            return this;
1✔
507
        }
508

509
        public Builder withProgressCallback(@Nullable ProgressCallback progressCallback) {
510
            this.progressCallback = progressCallback;
1✔
511
            return this;
1✔
512
        }
513

514
        /**
515
         * Set of context IDs to use in generation. Only the contexts with an id specified in this set will run.
516
         * If the set is empty, then all contexts are run.
517
         *
518
         * @param contextIds
519
         *            a set of contextIds to use in code generation
520
         *
521
         * @return this builder
522
         */
523
        public Builder withContextIds(Set<String> contextIds) {
524
            this.contextIds.addAll(contextIds);
1✔
525
            return this;
1✔
526
        }
527

528
        /**
529
         *  Set of table names to generate. The elements of the set must be Strings that exactly match what's
530
         *  specified in the configuration. For example, if a table name = "foo" and schema = "bar", then the fully
531
         *  qualified table name is "foo.bar". If the Set is empty, then all tables in the configuration
532
         *  will be used for code generation.
533
         *
534
         * @param fullyQualifiedTableNames
535
         *            a set of table names to use in code generation
536
         *
537
         * @return this builder
538
         */
539
        public Builder withFullyQualifiedTableNames(Set<String> fullyQualifiedTableNames) {
540
            this.fullyQualifiedTableNames.addAll(fullyQualifiedTableNames);
1✔
541
            return this;
1✔
542
        }
543

544
        /**
545
         * If true, then newly generated files will overwrite existing files if there is a collision.
546
         * If false, then newly generated files will be written with a unique name when there is a collision.
547
         *
548
         * <p>The default is <code>false</code></p>
549
         *
550
         * @param overwriteEnabled where newly generated files should overwrite existing files if there is a collision
551
         * @return this builder
552
         */
553
        public Builder withOverwriteEnabled(boolean overwriteEnabled) {
554
            this.isOverwriteEnabled = overwriteEnabled;
1✔
555
            return this;
1✔
556
        }
557

558
        /**
559
         * If true, then newly generated Java files will be merged if they collide with existing files.
560
         * If false, then the {@link #withOverwriteEnabled(boolean)} value governs what happens on a collision.
561
         *
562
         * <p>The default is <code>false</code></p>
563
         *
564
         * @param javaFileMergeEnabled where the Java file merger support should be enabled
565
         * @return this builder
566
         */
567
        public Builder withJavaFileMergeEnabled(boolean javaFileMergeEnabled) {
568
            this.isJavaFileMergeEnabled = javaFileMergeEnabled;
1✔
569
            return this;
1✔
570
        }
571

572
        /**
573
         * Specify an indenter to use if no indenters are configured in the configuration.
574
         * If not specified, then the library will use the default indenter.
575
         *
576
         * @param indenter an indenter to use if no indenters are configured. This indenter will not override
577
         *                 indenters specified in a configuration.
578
         * @return this builder
579
         */
580
        public Builder withIndenter(Indenter indenter) {
581
            this.indenter = indenter;
×
582
            return this;
×
583
        }
584

585
        public MyBatisGenerator build() {
586
            return new MyBatisGenerator(this);
1✔
587
        }
588
    }
589
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc