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

mybatis / generator / 2136

02 Apr 2026 07:17PM UTC coverage: 91.775% (+1.4%) from 90.382%
2136

Pull #1485

github

web-flow
Merge 516685a9a into 18f1f002d
Pull Request #1485: Code Cleanup and Coverage

2425 of 3124 branches covered (77.62%)

191 of 235 new or added lines in 54 files covered. (81.28%)

7 existing lines in 4 files now uncovered.

11884 of 12949 relevant lines covered (91.78%)

0.92 hits per line

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

83.15
/core/mybatis-generator-core/src/main/java/org/mybatis/generator/config/TableConfiguration.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.config;
17

18
import static org.mybatis.generator.internal.util.StringUtility.composeFullyQualifiedTableName;
19
import static org.mybatis.generator.internal.util.StringUtility.isTrue;
20
import static org.mybatis.generator.internal.util.StringUtility.stringHasValue;
21

22
import java.util.ArrayList;
23
import java.util.Collections;
24
import java.util.HashMap;
25
import java.util.List;
26
import java.util.Map;
27
import java.util.Objects;
28
import java.util.Optional;
29
import java.util.Properties;
30

31
import org.jspecify.annotations.Nullable;
32
import org.mybatis.generator.api.KnownRuntime;
33
import org.mybatis.generator.internal.util.messages.Messages;
34

35
public class TableConfiguration extends PropertyHolder {
36
    private final boolean insertStatementEnabled;
37
    private final boolean selectByPrimaryKeyStatementEnabled;
38
    private final boolean selectByExampleStatementEnabled;
39
    private final boolean updateByPrimaryKeyStatementEnabled;
40
    private final boolean deleteByPrimaryKeyStatementEnabled;
41
    private final boolean deleteByExampleStatementEnabled;
42
    private final boolean countByExampleStatementEnabled;
43
    private final boolean updateByExampleStatementEnabled;
44
    private final List<ColumnOverride> columnOverrides;
45
    // this is a Map for validation purposes. Initially, all items will be FALSE. When accessed, an item will
46
    // be made TRUE. This allows us to generate warning for columns configured to be ignored but not found.
47
    private final Map<IgnoredColumn, Boolean> ignoredColumns;
48
    private final @Nullable GeneratedKey generatedKey;
49
    private final @Nullable String catalog;
50
    private final @Nullable String schema;
51
    private final String tableName;
52
    private final @Nullable String domainObjectName;
53
    private final @Nullable String alias;
54
    private final @Nullable ModelType modelType;
55
    private final boolean wildcardEscapingEnabled;
56
    private final boolean delimitIdentifiers;
57
    private final @Nullable DomainObjectRenamingRule domainObjectRenamingRule;
58
    private final @Nullable ColumnRenamingRule columnRenamingRule;
59
    private final boolean isAllColumnDelimitingEnabled;
60
    private final @Nullable String mapperName;
61
    private final @Nullable String sqlProviderName;
62
    private final List<IgnoredColumnPattern> ignoredColumnPatterns;
63
    private final String fullyQualifiedName;
64

65
    protected TableConfiguration(Builder builder) {
66
        super(builder);
1✔
67

68
        catalog = builder.catalog;
1✔
69
        schema = builder.schema;
1✔
70
        tableName = Objects.requireNonNull(builder.tableName);
1✔
71
        domainObjectName = builder.domainObjectName;
1✔
72
        alias = builder.alias;
1✔
73
        modelType = builder.modelType;
1✔
74
        insertStatementEnabled = builder.insertStatementEnabled;
1✔
75
        selectByPrimaryKeyStatementEnabled = builder.selectByPrimaryKeyStatementEnabled;
1✔
76
        selectByExampleStatementEnabled = builder.selectByExampleStatementEnabled;
1✔
77
        updateByPrimaryKeyStatementEnabled = builder.updateByPrimaryKeyStatementEnabled;
1✔
78
        deleteByPrimaryKeyStatementEnabled = builder.deleteByPrimaryKeyStatementEnabled;
1✔
79
        deleteByExampleStatementEnabled = builder.deleteByExampleStatementEnabled;
1✔
80
        countByExampleStatementEnabled = builder.countByExampleStatementEnabled;
1✔
81
        updateByExampleStatementEnabled = builder.updateByExampleStatementEnabled;
1✔
82
        wildcardEscapingEnabled = builder.wildcardEscapingEnabled;
1✔
83
        delimitIdentifiers = builder.delimitIdentifiers;
1✔
84
        isAllColumnDelimitingEnabled = builder.isAllColumnDelimitingEnabled;
1✔
85
        mapperName = builder.mapperName;
1✔
86
        sqlProviderName = builder.sqlProviderName;
1✔
87
        columnOverrides = Collections.unmodifiableList(builder.columnOverrides);
1✔
88
        ignoredColumns = builder.ignoredColumns;
1✔
89
        generatedKey = builder.generatedKey;
1✔
90
        domainObjectRenamingRule = builder.domainObjectRenamingRule;
1✔
91
        columnRenamingRule = builder.columnRenamingRule;
1✔
92
        ignoredColumnPatterns = Collections.unmodifiableList(builder.ignoredColumnPatterns);
1✔
93
        fullyQualifiedName = composeFullyQualifiedTableName(catalog, schema, tableName, '.');
1✔
94
    }
1✔
95

96
    public boolean isDeleteByPrimaryKeyStatementEnabled() {
97
        return deleteByPrimaryKeyStatementEnabled;
1✔
98
    }
99

100
    public boolean isInsertStatementEnabled() {
101
        return insertStatementEnabled;
1✔
102
    }
103

104
    public boolean isSelectByPrimaryKeyStatementEnabled() {
105
        return selectByPrimaryKeyStatementEnabled;
1✔
106
    }
107

108
    public boolean isUpdateByPrimaryKeyStatementEnabled() {
109
        return updateByPrimaryKeyStatementEnabled;
1✔
110
    }
111

112
    public boolean isColumnIgnored(String columnName) {
113
        for (Map.Entry<IgnoredColumn, Boolean> entry : ignoredColumns.entrySet()) {
1✔
114
            if (entry.getKey().matches(columnName)) {
1✔
115
                entry.setValue(Boolean.TRUE);
1✔
116
                return true;
1✔
117
            }
118
        }
1✔
119

120
        for (IgnoredColumnPattern ignoredColumnPattern : ignoredColumnPatterns) {
1✔
121
            if (ignoredColumnPattern.matches(columnName)) {
1✔
122
                return true;
1✔
123
            }
124
        }
1✔
125

126
        return false;
1✔
127
    }
128

129
    @Override
130
    public boolean equals(Object obj) {
131
        if (this == obj) {
×
132
            return true;
×
133
        }
134

135
        if (!(obj instanceof TableConfiguration other)) {
×
136
            return false;
×
137
        }
138

139
        return Objects.equals(this.catalog, other.catalog)
×
140
                && Objects.equals(this.schema, other.schema)
×
141
                && Objects.equals(this.tableName, other.tableName);
×
142
    }
143

144
    @Override
145
    public int hashCode() {
146
        return Objects.hash(catalog, schema, tableName);
×
147
    }
148

149
    public boolean isSelectByExampleStatementEnabled() {
150
        return selectByExampleStatementEnabled;
1✔
151
    }
152

153
    /**
154
     * May return null if the column has not been overridden.
155
     *
156
     * @param columnName
157
     *            the column name
158
     * @return the column override (if any) related to this column
159
     */
160
    public Optional<ColumnOverride> getColumnOverride(String columnName) {
161
        for (ColumnOverride co : columnOverrides) {
1✔
162
            if (co.isColumnNameDelimited()) {
1✔
163
                if (columnName.equals(co.getColumnName())) {
1✔
164
                    return Optional.of(co);
1✔
165
                }
166
            } else {
167
                if (columnName.equalsIgnoreCase(co.getColumnName())) {
1✔
168
                    return Optional.of(co);
1✔
169
                }
170
            }
171
        }
1✔
172

173
        return Optional.empty();
1✔
174
    }
175

176
    public Optional<GeneratedKey> getGeneratedKey() {
177
        return Optional.ofNullable(generatedKey);
1✔
178
    }
179

180
    public boolean isDeleteByExampleStatementEnabled() {
181
        return deleteByExampleStatementEnabled;
1✔
182
    }
183

184
    public boolean areAnyStatementsEnabled() {
185
        return selectByExampleStatementEnabled
1!
186
                || selectByPrimaryKeyStatementEnabled || insertStatementEnabled
187
                || updateByPrimaryKeyStatementEnabled
188
                || deleteByExampleStatementEnabled
189
                || deleteByPrimaryKeyStatementEnabled
190
                || countByExampleStatementEnabled
191
                || updateByExampleStatementEnabled;
192
    }
193

194
    public @Nullable String getAlias() {
195
        return alias;
1✔
196
    }
197

198
    public @Nullable String getCatalog() {
199
        return catalog;
1✔
200
    }
201

202
    public @Nullable String getDomainObjectName() {
203
        return domainObjectName;
1✔
204
    }
205

206
    public @Nullable String getSchema() {
207
        return schema;
1✔
208
    }
209

210
    public String getTableName() {
211
        return tableName;
1✔
212
    }
213

214
    public String getFullyQualifiedName() {
215
        return fullyQualifiedName;
1✔
216
    }
217

218
    public List<ColumnOverride> getColumnOverrides() {
219
        return columnOverrides;
1✔
220
    }
221

222
    /**
223
     * Returns a List of Strings. The values are the columns
224
     * that were specified to be ignored in the table but do not exist in the
225
     * table.
226
     *
227
     * @return a List of Strings - the columns that were improperly configured
228
     *         as ignored columns
229
     */
230
    public List<String> getIgnoredColumnsInError() {
231
        List<String> answer = new ArrayList<>();
1✔
232

233
        for (Map.Entry<IgnoredColumn, Boolean> entry : ignoredColumns.entrySet()) {
1✔
234
            if (Boolean.FALSE.equals(entry.getValue())) {
1✔
235
                answer.add(entry.getKey().getColumnName());
1✔
236
            }
237
        }
1✔
238

239
        return answer;
1✔
240
    }
241

242
    public Optional<ModelType> getModelType() {
243
        return Optional.ofNullable(modelType);
1✔
244
    }
245

246
    public boolean isWildcardEscapingEnabled() {
247
        return wildcardEscapingEnabled;
1✔
248
    }
249

250
    @Override
251
    public String toString() {
NEW
252
        return fullyQualifiedName;
×
253
    }
254

255
    public boolean isDelimitIdentifiers() {
256
        return delimitIdentifiers;
1✔
257
    }
258

259
    public boolean isCountByExampleStatementEnabled() {
260
        return countByExampleStatementEnabled;
1✔
261
    }
262

263
    public boolean isUpdateByExampleStatementEnabled() {
264
        return updateByExampleStatementEnabled;
1✔
265
    }
266

267
    public void validate(List<String> errors, int listPosition, Context context, KnownRuntime knownRuntime) {
268
        if (!stringHasValue(tableName)) {
1!
269
            errors.add(Messages.getString(
×
270
                    "ValidationError.6", Integer.toString(listPosition))); //$NON-NLS-1$
×
271
        }
272

273
        if (generatedKey != null) {
1✔
274
            // if the model type is immutable or record, then we cannot have generated keys
275
            ModelType mt = getModelType().orElseGet(context::getDefaultModelType);
1✔
276
            if (mt == ModelType.RECORD) {
1✔
277
                errors.add(Messages.getString("ValidationError.30", fullyQualifiedName, context.getId(), //$NON-NLS-1$
1✔
278
                        "record")); //$NON-NLS-1$
279
            }
280

281
            // we're going to allow generated keys for Kotlin even if the rest of the model is immutable
282
            if (isImmutable(context) && knownRuntime != KnownRuntime.MYBATIS3_KOTLIN) {
1!
283
                errors.add(Messages.getString("ValidationError.30", fullyQualifiedName, context.getId(), //$NON-NLS-1$
1✔
284
                        "immutable")); //$NON-NLS-1$
285
            }
286

287
            generatedKey.validate(errors, fullyQualifiedName, context.getId());
1✔
288
        }
289

290
        if (domainObjectRenamingRule != null) {
1✔
291
            domainObjectRenamingRule.validate(errors, fullyQualifiedName);
1✔
292
        }
293

294
        if (columnRenamingRule != null) {
1✔
295
            columnRenamingRule.validate(errors, fullyQualifiedName);
1✔
296
        }
297

298
        for (ColumnOverride columnOverride : columnOverrides) {
1✔
299
            columnOverride.validate(errors, fullyQualifiedName);
1✔
300
        }
1✔
301

302
        for (IgnoredColumn ignoredColumn : ignoredColumns.keySet()) {
1✔
303
            ignoredColumn.validate(errors, fullyQualifiedName);
1✔
304
        }
1✔
305

306
        for (IgnoredColumnPattern ignoredColumnPattern : ignoredColumnPatterns) {
1✔
307
            ignoredColumnPattern.validate(errors, fullyQualifiedName);
1✔
308
        }
1✔
309
    }
1✔
310

311
    public boolean isImmutable(Context context) {
312
        Properties properties;
313

314
        if (getProperties().containsKey(PropertyRegistry.ANY_IMMUTABLE)) {
1✔
315
            properties = getProperties();
1✔
316
        } else {
317
            properties = context.getModelGeneratorConfiguration().getProperties();
1✔
318
        }
319

320
        return isTrue(properties.getProperty(PropertyRegistry.ANY_IMMUTABLE));
1✔
321
    }
322

323
    public boolean generateKotlinV1Model(Context context) {
324
        Properties properties;
325

326
        if (getProperties().containsKey(PropertyRegistry.GENERATE_KOTLIN_V1_MODEL)) {
1✔
327
            properties = getProperties();
1✔
328
        } else {
329
            properties = context.getModelGeneratorConfiguration().getProperties();
1✔
330
        }
331

332
        return isTrue(properties.getProperty(PropertyRegistry.GENERATE_KOTLIN_V1_MODEL));
1✔
333
    }
334

335
    public @Nullable DomainObjectRenamingRule getDomainObjectRenamingRule() {
336
        return domainObjectRenamingRule;
1✔
337
    }
338

339
    public Optional<ColumnRenamingRule> getColumnRenamingRule() {
340
        return Optional.ofNullable(columnRenamingRule);
1✔
341
    }
342

343
    public boolean isAllColumnDelimitingEnabled() {
344
        return isAllColumnDelimitingEnabled;
1✔
345
    }
346

347
    public @Nullable String getMapperName() {
348
        return mapperName;
1✔
349
    }
350

351
    public @Nullable String getSqlProviderName() {
352
        return sqlProviderName;
1✔
353
    }
354

355
    public @Nullable String getDynamicSqlSupportClassName() {
356
        return getProperty(PropertyRegistry.TABLE_DYNAMIC_SQL_SUPPORT_CLASS_NAME);
1✔
357
    }
358

359
    public @Nullable String getDynamicSqlTableObjectName() {
360
        return getProperty(PropertyRegistry.TABLE_DYNAMIC_SQL_TABLE_OBJECT_NAME);
1✔
361
    }
362

363
    public static class Builder extends AbstractBuilder<Builder> {
1✔
364
        private @Nullable ModelType modelType;
365
        private @Nullable String catalog;
366
        private @Nullable String schema;
367
        private @Nullable String tableName;
368
        private @Nullable String domainObjectName;
369
        private @Nullable String alias;
370
        private boolean insertStatementEnabled = true;
1✔
371
        private boolean selectByPrimaryKeyStatementEnabled = true;
1✔
372
        private boolean selectByExampleStatementEnabled = true;
1✔
373
        private boolean updateByPrimaryKeyStatementEnabled = true;
1✔
374
        private boolean deleteByPrimaryKeyStatementEnabled = true;
1✔
375
        private boolean deleteByExampleStatementEnabled = true;
1✔
376
        private boolean countByExampleStatementEnabled = true;
1✔
377
        private boolean updateByExampleStatementEnabled = true;
1✔
378
        private boolean wildcardEscapingEnabled;
379
        private boolean delimitIdentifiers;
380
        private boolean isAllColumnDelimitingEnabled;
381
        private @Nullable String mapperName;
382
        private @Nullable String sqlProviderName;
383
        private @Nullable GeneratedKey generatedKey;
384
        private @Nullable DomainObjectRenamingRule domainObjectRenamingRule;
385
        private @Nullable ColumnRenamingRule columnRenamingRule;
386
        private final List<IgnoredColumnPattern> ignoredColumnPatterns = new ArrayList<>();
1✔
387
        private final List<ColumnOverride> columnOverrides = new ArrayList<>();
1✔
388
        private final Map<IgnoredColumn, Boolean> ignoredColumns = new HashMap<>();
1✔
389

390
        public TableConfiguration build() {
391
            return new TableConfiguration(this);
1✔
392
        }
393

394
        @Override
395
        protected Builder getThis() {
396
            return this;
1✔
397
        }
398

399
        public Builder withModelType(@Nullable String tableModelType) {
400
            this.modelType = tableModelType == null ? null : ModelType.getModelType(tableModelType);
1✔
401
            return getThis();
1✔
402
        }
403

404
        public Builder withCatalog(@Nullable String catalog) {
405
            this.catalog = catalog;
1✔
406
            return this;
1✔
407
        }
408

409
        public Builder withSchema(@Nullable String schema) {
410
            this.schema = schema;
1✔
411
            return this;
1✔
412
        }
413

414
        public Builder withTableName(@Nullable String tableName) {
415
            this.tableName = tableName;
1✔
416
            return this;
1✔
417
        }
418

419
        public Builder withDomainObjectName(@Nullable String domainObjectName) {
420
            this.domainObjectName = domainObjectName;
1✔
421
            return this;
1✔
422
        }
423

424
        public Builder withAlias(@Nullable String alias) {
425
            this.alias = alias;
1✔
426
            return this;
1✔
427
        }
428

429
        @SuppressWarnings("UnusedReturnValue")
430
        public Builder withInsertStatementEnabled(boolean insertStatementEnabled) {
431
            this.insertStatementEnabled = insertStatementEnabled;
×
432
            return this;
×
433
        }
434

435
        @SuppressWarnings("UnusedReturnValue")
436
        public Builder withSelectByPrimaryKeyStatementEnabled(boolean selectByPrimaryKeyStatementEnabled) {
437
            this.selectByPrimaryKeyStatementEnabled = selectByPrimaryKeyStatementEnabled;
×
438
            return this;
×
439
        }
440

441
        @SuppressWarnings("UnusedReturnValue")
442
        public Builder withSelectByExampleStatementEnabled(boolean selectByExampleStatementEnabled) {
443
            this.selectByExampleStatementEnabled = selectByExampleStatementEnabled;
1✔
444
            return this;
1✔
445
        }
446

447
        @SuppressWarnings("UnusedReturnValue")
448
        public Builder withUpdateByPrimaryKeyStatementEnabled(boolean updateByPrimaryKeyStatementEnabled) {
449
            this.updateByPrimaryKeyStatementEnabled = updateByPrimaryKeyStatementEnabled;
×
450
            return this;
×
451
        }
452

453
        @SuppressWarnings("UnusedReturnValue")
454
        public Builder withDeleteByPrimaryKeyStatementEnabled(boolean deleteByPrimaryKeyStatementEnabled) {
455
            this.deleteByPrimaryKeyStatementEnabled = deleteByPrimaryKeyStatementEnabled;
×
456
            return this;
×
457
        }
458

459
        @SuppressWarnings("UnusedReturnValue")
460
        public Builder withDeleteByExampleStatementEnabled(boolean deleteByExampleStatementEnabled) {
461
            this.deleteByExampleStatementEnabled = deleteByExampleStatementEnabled;
×
462
            return this;
×
463
        }
464

465
        @SuppressWarnings("UnusedReturnValue")
466
        public Builder withCountByExampleStatementEnabled(boolean countByExampleStatementEnabled) {
467
            this.countByExampleStatementEnabled = countByExampleStatementEnabled;
×
468
            return this;
×
469
        }
470

471
        @SuppressWarnings("UnusedReturnValue")
472
        public Builder withUpdateByExampleStatementEnabled(boolean updateByExampleStatementEnabled) {
473
            this.updateByExampleStatementEnabled = updateByExampleStatementEnabled;
×
474
            return this;
×
475
        }
476

477
        @SuppressWarnings("UnusedReturnValue")
478
        public Builder withWildcardEscapingEnabled(boolean wildcardEscapingEnabled) {
479
            this.wildcardEscapingEnabled = wildcardEscapingEnabled;
×
480
            return this;
×
481
        }
482

483
        @SuppressWarnings("UnusedReturnValue")
484
        public Builder withDelimitIdentifiers(boolean delimitIdentifiers) {
485
            this.delimitIdentifiers = delimitIdentifiers;
×
486
            return this;
×
487
        }
488

489
        @SuppressWarnings("UnusedReturnValue")
490
        public Builder withAllColumnDelimitingEnabled(boolean isAllColumnDelimitingEnabled) {
491
            this.isAllColumnDelimitingEnabled = isAllColumnDelimitingEnabled;
×
492
            return this;
×
493
        }
494

495
        public Builder withMapperName(@Nullable String mapperName) {
496
            this.mapperName = mapperName;
1✔
497
            return this;
1✔
498
        }
499

500
        public Builder withSqlProviderName(@Nullable String sqlProviderName) {
501
            this.sqlProviderName = sqlProviderName;
1✔
502
            return this;
1✔
503
        }
504

505
        @SuppressWarnings("UnusedReturnValue")
506
        public Builder withGeneratedKey(@Nullable GeneratedKey generatedKey) {
507
            this.generatedKey = generatedKey;
1✔
508
            return this;
1✔
509
        }
510

511
        @SuppressWarnings("UnusedReturnValue")
512
        public Builder withDomainObjectRenamingRule(@Nullable DomainObjectRenamingRule domainObjectRenamingRule) {
513
            this.domainObjectRenamingRule = domainObjectRenamingRule;
1✔
514
            return this;
1✔
515
        }
516

517
        @SuppressWarnings("UnusedReturnValue")
518
        public Builder withColumnRenamingRule(@Nullable ColumnRenamingRule columnRenamingRule) {
519
            this.columnRenamingRule = columnRenamingRule;
1✔
520
            return this;
1✔
521
        }
522

523
        @SuppressWarnings("UnusedReturnValue")
524
        public Builder withIgnoredColumnPattern(IgnoredColumnPattern ignoredColumnPattern) {
525
            this.ignoredColumnPatterns.add(ignoredColumnPattern);
1✔
526
            return this;
1✔
527
        }
528

529
        @SuppressWarnings("UnusedReturnValue")
530
        public Builder withIgnoredColumn(IgnoredColumn ignoredColumn) {
531
            this.ignoredColumns.put(ignoredColumn, Boolean.FALSE);
1✔
532
            return this;
1✔
533
        }
534

535
        @SuppressWarnings("UnusedReturnValue")
536
        public Builder withColumnOverride(ColumnOverride columnOverride) {
537
            this.columnOverrides.add(columnOverride);
1✔
538
            return this;
1✔
539
        }
540
    }
541
}
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