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

mybatis / generator / 1947

14 Jan 2026 02:31PM UTC coverage: 88.838% (+0.04%) from 88.799%
1947

push

github

web-flow
Merge pull request #1411 from mybatis/renovate/github-codeql-action-digest

Update github/codeql-action digest to cdefb33

2347 of 3184 branches covered (73.71%)

11517 of 12964 relevant lines covered (88.84%)

0.89 hits per line

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

78.03
/core/mybatis-generator-core/src/main/java/org/mybatis/generator/plugins/EqualsHashCodePlugin.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.plugins;
17

18
import static org.mybatis.generator.internal.util.JavaBeansUtil.getGetterMethodName;
19
import static org.mybatis.generator.internal.util.StringUtility.isTrue;
20

21
import java.util.Iterator;
22
import java.util.List;
23
import java.util.Properties;
24

25
import org.mybatis.generator.api.IntrospectedColumn;
26
import org.mybatis.generator.api.IntrospectedTable;
27
import org.mybatis.generator.api.IntrospectedTable.TargetRuntime;
28
import org.mybatis.generator.api.PluginAdapter;
29
import org.mybatis.generator.api.dom.OutputUtilities;
30
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
31
import org.mybatis.generator.api.dom.java.JavaVisibility;
32
import org.mybatis.generator.api.dom.java.Method;
33
import org.mybatis.generator.api.dom.java.Parameter;
34
import org.mybatis.generator.api.dom.java.TopLevelClass;
35

36
/**
37
 * This plugin adds equals() and hashCode() methods to the generated model
38
 * classes. It demonstrates the process of adding methods to generated classes
39
 *
40
 * <p>The <code>equals</code> method generated by this class is correct in most cases,
41
 * but will probably NOT be correct if you have specified a rootClass - because
42
 * our equals method only checks the fields it knows about.
43
 *
44
 * <p>Similarly, the <code>hashCode</code> method generated by this class only relies
45
 * on fields it knows about. Anything you add, or fields in a super class will
46
 * not be factored into the hash code.
47
 *
48
 * @author Jeff Butler
49
 *
50
 */
51
public class EqualsHashCodePlugin extends PluginAdapter {
1✔
52

53
    private boolean useEqualsHashCodeFromRoot;
54

55
    @Override
56
    public void setProperties(Properties properties) {
57
        super.setProperties(properties);
1✔
58
        useEqualsHashCodeFromRoot = isTrue(properties.getProperty("useEqualsHashCodeFromRoot")); //$NON-NLS-1$
1✔
59
    }
1✔
60

61
    /**
62
     * This plugin is always valid - no properties are required.
63
     */
64
    @Override
65
    public boolean validate(List<String> warnings) {
66
        return true;
1✔
67
    }
68

69
    @Override
70
    public boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass,
71
            IntrospectedTable introspectedTable) {
72
        List<IntrospectedColumn> columns;
73
        if (introspectedTable.getRules().generateRecordWithBLOBsClass()) {
1✔
74
            columns = introspectedTable.getNonBLOBColumns();
1✔
75
        } else {
76
            columns = introspectedTable.getAllColumns();
1✔
77
        }
78

79
        generateEquals(topLevelClass, columns, introspectedTable);
1✔
80
        generateHashCode(topLevelClass, columns, introspectedTable);
1✔
81

82
        return true;
1✔
83
    }
84

85
    @Override
86
    public boolean modelPrimaryKeyClassGenerated(TopLevelClass topLevelClass,
87
            IntrospectedTable introspectedTable) {
88
        generateEquals(topLevelClass, introspectedTable.getPrimaryKeyColumns(),
1✔
89
                introspectedTable);
90
        generateHashCode(topLevelClass, introspectedTable
1✔
91
                .getPrimaryKeyColumns(), introspectedTable);
1✔
92

93
        return true;
1✔
94
    }
95

96
    @Override
97
    public boolean modelRecordWithBLOBsClassGenerated(
98
            TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
99
        generateEquals(topLevelClass, introspectedTable.getAllColumns(),
1✔
100
                introspectedTable);
101
        generateHashCode(topLevelClass, introspectedTable.getAllColumns(),
1✔
102
                introspectedTable);
103

104
        return true;
1✔
105
    }
106

107
    /**
108
     * Generates an <code>equals</code> method that does a comparison of all fields.
109
     *
110
     * <p>The generated <code>equals</code> method will be correct unless:
111
     *
112
     * <ul>
113
     *   <li>Other fields have been added to the generated classes</li>
114
     *   <li>A <code>rootClass</code> is specified that holds state</li>
115
     * </ul>
116
     *
117
     * @param topLevelClass
118
     *            the class to which the method will be added
119
     * @param introspectedColumns
120
     *            column definitions of this class and any superclass of this
121
     *            class
122
     * @param introspectedTable
123
     *            the table corresponding to this class
124
     */
125
    protected void generateEquals(TopLevelClass topLevelClass,
126
            List<IntrospectedColumn> introspectedColumns,
127
            IntrospectedTable introspectedTable) {
128
        Method method = new Method("equals"); //$NON-NLS-1$
1✔
129
        method.setVisibility(JavaVisibility.PUBLIC);
1✔
130
        method.setReturnType(FullyQualifiedJavaType
1✔
131
                .getBooleanPrimitiveInstance());
1✔
132
        method.addParameter(new Parameter(FullyQualifiedJavaType
1✔
133
                .getObjectInstance(), "that")); //$NON-NLS-1$
1✔
134
        method.addAnnotation("@Override"); //$NON-NLS-1$
1✔
135

136
        if (introspectedTable.getTargetRuntime() == TargetRuntime.MYBATIS3_DSQL) {
1✔
137
            commentGenerator.addGeneralMethodAnnotation(method, introspectedTable, topLevelClass.getImportedTypes());
1✔
138
        } else {
139
            commentGenerator.addGeneralMethodComment(method, introspectedTable);
1✔
140
        }
141

142
        method.addBodyLine("if (this == that) {"); //$NON-NLS-1$
1✔
143
        method.addBodyLine("return true;"); //$NON-NLS-1$
1✔
144
        method.addBodyLine("}"); //$NON-NLS-1$
1✔
145

146
        method.addBodyLine("if (that == null) {"); //$NON-NLS-1$
1✔
147
        method.addBodyLine("return false;"); //$NON-NLS-1$
1✔
148
        method.addBodyLine("}"); //$NON-NLS-1$
1✔
149

150
        method.addBodyLine("if (getClass() != that.getClass()) {"); //$NON-NLS-1$
1✔
151
        method.addBodyLine("return false;"); //$NON-NLS-1$
1✔
152
        method.addBodyLine("}"); //$NON-NLS-1$
1✔
153

154
        StringBuilder sb = new StringBuilder();
1✔
155
        sb.append(topLevelClass.getType().getShortName());
1✔
156
        sb.append(" other = ("); //$NON-NLS-1$
1✔
157
        sb.append(topLevelClass.getType().getShortName());
1✔
158
        sb.append(") that;"); //$NON-NLS-1$
1✔
159
        method.addBodyLine(sb.toString());
1✔
160

161
        if (useEqualsHashCodeFromRoot && topLevelClass.getSuperClass().isPresent()) {
1!
162
            method.addBodyLine("if (!super.equals(other)) {"); //$NON-NLS-1$
×
163
            method.addBodyLine("return false;"); //$NON-NLS-1$
×
164
            method.addBodyLine("}"); //$NON-NLS-1$
×
165
        }
166

167
        boolean first = true;
1✔
168
        Iterator<IntrospectedColumn> iter = introspectedColumns.iterator();
1✔
169
        while (iter.hasNext()) {
1✔
170
            IntrospectedColumn introspectedColumn = iter.next();
1✔
171

172
            sb.setLength(0);
1✔
173

174
            if (first) {
1✔
175
                sb.append("return ("); //$NON-NLS-1$
1✔
176
                first = false;
1✔
177
            } else {
178
                OutputUtilities.javaIndent(sb, 1);
1✔
179
                sb.append("&& ("); //$NON-NLS-1$
1✔
180
            }
181

182
            String getterMethod = getGetterMethodName(
1✔
183
                    introspectedColumn.getJavaProperty(), introspectedColumn
1✔
184
                            .getFullyQualifiedJavaType());
1✔
185

186
            if (introspectedColumn.getFullyQualifiedJavaType().isPrimitive()) {
1✔
187
                sb.append("this."); //$NON-NLS-1$
1✔
188
                sb.append(getterMethod);
1✔
189
                sb.append("() == "); //$NON-NLS-1$
1✔
190
                sb.append("other."); //$NON-NLS-1$
1✔
191
                sb.append(getterMethod);
1✔
192
                sb.append("())"); //$NON-NLS-1$
1✔
193
            } else if (introspectedColumn.getFullyQualifiedJavaType().isArray()) {
1✔
194
                topLevelClass.addImportedType("java.util.Arrays"); //$NON-NLS-1$
1✔
195
                sb.append("Arrays.equals(this."); //$NON-NLS-1$
1✔
196
                sb.append(getterMethod);
1✔
197
                sb.append("(), "); //$NON-NLS-1$
1✔
198
                sb.append("other."); //$NON-NLS-1$
1✔
199
                sb.append(getterMethod);
1✔
200
                sb.append("()))"); //$NON-NLS-1$
1✔
201
            } else {
202
                sb.append("this."); //$NON-NLS-1$
1✔
203
                sb.append(getterMethod);
1✔
204
                sb.append("() == null ? other."); //$NON-NLS-1$
1✔
205
                sb.append(getterMethod);
1✔
206
                sb.append("() == null : this."); //$NON-NLS-1$
1✔
207
                sb.append(getterMethod);
1✔
208
                sb.append("().equals(other."); //$NON-NLS-1$
1✔
209
                sb.append(getterMethod);
1✔
210
                sb.append("()))"); //$NON-NLS-1$
1✔
211
            }
212

213
            if (!iter.hasNext()) {
1✔
214
                sb.append(';');
1✔
215
            }
216

217
            method.addBodyLine(sb.toString());
1✔
218
        }
1✔
219

220
        topLevelClass.addMethod(method);
1✔
221
    }
1✔
222

223
    /**
224
     * Generates a <code>hashCode</code> method that includes all fields.
225
     *
226
     * <p>Note that this implementation is based on the eclipse foundation hashCode
227
     * generator.
228
     *
229
     * @param topLevelClass
230
     *            the class to which the method will be added
231
     * @param introspectedColumns
232
     *            column definitions of this class and any superclass of this
233
     *            class
234
     * @param introspectedTable
235
     *            the table corresponding to this class
236
     */
237
    protected void generateHashCode(TopLevelClass topLevelClass,
238
            List<IntrospectedColumn> introspectedColumns,
239
            IntrospectedTable introspectedTable) {
240
        Method method = new Method("hashCode"); //$NON-NLS-1$
1✔
241
        method.setVisibility(JavaVisibility.PUBLIC);
1✔
242
        method.setReturnType(FullyQualifiedJavaType.getIntInstance());
1✔
243
        method.addAnnotation("@Override"); //$NON-NLS-1$
1✔
244

245
        if (introspectedTable.getTargetRuntime() == TargetRuntime.MYBATIS3_DSQL) {
1✔
246
            commentGenerator.addGeneralMethodAnnotation(method, introspectedTable, topLevelClass.getImportedTypes());
1✔
247
        } else {
248
            commentGenerator.addGeneralMethodComment(method, introspectedTable);
1✔
249
        }
250

251
        method.addBodyLine("final int prime = 31;"); //$NON-NLS-1$
1✔
252
        method.addBodyLine("int result = 1;"); //$NON-NLS-1$
1✔
253

254
        if (useEqualsHashCodeFromRoot && topLevelClass.getSuperClass().isPresent()) {
1!
255
            method.addBodyLine("result = prime * result + super.hashCode();"); //$NON-NLS-1$
×
256
        }
257

258
        StringBuilder sb = new StringBuilder();
1✔
259
        boolean hasTemp = false;
1✔
260
        for (IntrospectedColumn introspectedColumn : introspectedColumns) {
1✔
261
            FullyQualifiedJavaType fqjt = introspectedColumn
1✔
262
                    .getFullyQualifiedJavaType();
1✔
263

264
            String getterMethod = getGetterMethodName(
1✔
265
                    introspectedColumn.getJavaProperty(), fqjt);
1✔
266

267
            sb.setLength(0);
1✔
268
            if (fqjt.isPrimitive()) {
1✔
269
                if ("boolean".equals(fqjt.getFullyQualifiedName())) { //$NON-NLS-1$
1✔
270
                    sb.append("result = prime * result + ("); //$NON-NLS-1$
1✔
271
                    sb.append(getterMethod);
1✔
272
                    sb.append("() ? 1231 : 1237);"); //$NON-NLS-1$
1✔
273
                    method.addBodyLine(sb.toString());
1✔
274
                } else if ("byte".equals(fqjt.getFullyQualifiedName())) { //$NON-NLS-1$
1!
275
                    sb.append("result = prime * result + "); //$NON-NLS-1$
×
276
                    sb.append(getterMethod);
×
277
                    sb.append("();"); //$NON-NLS-1$
×
278
                    method.addBodyLine(sb.toString());
×
279
                } else if ("char".equals(fqjt.getFullyQualifiedName())) { //$NON-NLS-1$
1!
280
                    sb.append("result = prime * result + "); //$NON-NLS-1$
×
281
                    sb.append(getterMethod);
×
282
                    sb.append("();"); //$NON-NLS-1$
×
283
                    method.addBodyLine(sb.toString());
×
284
                } else if ("double".equals(fqjt.getFullyQualifiedName())) { //$NON-NLS-1$
1!
285
                    if (!hasTemp) {
×
286
                        method.addBodyLine("long temp;"); //$NON-NLS-1$
×
287
                        hasTemp = true;
×
288
                    }
289
                    sb.append("temp = Double.doubleToLongBits("); //$NON-NLS-1$
×
290
                    sb.append(getterMethod);
×
291
                    sb.append("());"); //$NON-NLS-1$
×
292
                    method.addBodyLine(sb.toString());
×
293
                    method
×
294
                            .addBodyLine("result = prime * result + (int) (temp ^ (temp >>> 32));"); //$NON-NLS-1$
×
295
                } else if ("float".equals(fqjt.getFullyQualifiedName())) { //$NON-NLS-1$
1!
296
                    sb
×
297
                            .append("result = prime * result + Float.floatToIntBits("); //$NON-NLS-1$
×
298
                    sb.append(getterMethod);
×
299
                    sb.append("());"); //$NON-NLS-1$
×
300
                    method.addBodyLine(sb.toString());
×
301
                } else if ("int".equals(fqjt.getFullyQualifiedName())) { //$NON-NLS-1$
1!
302
                    sb.append("result = prime * result + "); //$NON-NLS-1$
1✔
303
                    sb.append(getterMethod);
1✔
304
                    sb.append("();"); //$NON-NLS-1$
1✔
305
                    method.addBodyLine(sb.toString());
1✔
306
                } else if ("long".equals(fqjt.getFullyQualifiedName())) { //$NON-NLS-1$
×
307
                    sb.append("result = prime * result + (int) ("); //$NON-NLS-1$
×
308
                    sb.append(getterMethod);
×
309
                    sb.append("() ^ ("); //$NON-NLS-1$
×
310
                    sb.append(getterMethod);
×
311
                    sb.append("() >>> 32));"); //$NON-NLS-1$
×
312
                    method.addBodyLine(sb.toString());
×
313
                } else if ("short".equals(fqjt.getFullyQualifiedName())) { //$NON-NLS-1$
×
314
                    sb.append("result = prime * result + "); //$NON-NLS-1$
×
315
                    sb.append(getterMethod);
×
316
                    sb.append("();"); //$NON-NLS-1$
×
317
                    method.addBodyLine(sb.toString());
×
318
                }
319
            } else if (fqjt.isArray()) {
1✔
320
                // Arrays is already imported by the generateEquals method, we don't need
321
                // to do it again
322
                sb.append("result = prime * result + (Arrays.hashCode("); //$NON-NLS-1$
1✔
323
                sb.append(getterMethod);
1✔
324
                sb.append("()));"); //$NON-NLS-1$
1✔
325
                method.addBodyLine(sb.toString());
1✔
326
            } else {
327
                sb.append("result = prime * result + (("); //$NON-NLS-1$
1✔
328
                sb.append(getterMethod);
1✔
329
                sb.append("() == null) ? 0 : "); //$NON-NLS-1$
1✔
330
                sb.append(getterMethod);
1✔
331
                sb.append("().hashCode());"); //$NON-NLS-1$
1✔
332
                method.addBodyLine(sb.toString());
1✔
333
            }
334
        }
1✔
335

336
        method.addBodyLine("return result;"); //$NON-NLS-1$
1✔
337

338
        topLevelClass.addMethod(method);
1✔
339
    }
1✔
340
}
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