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

mybatis / generator / 1646

21 Apr 2025 10:17PM UTC coverage: 88.157% (-0.2%) from 88.328%
1646

push

github

hazendaz
[ci] Run auto formatting

2518 of 3412 branches covered (73.8%)

994 of 1117 new or added lines in 164 files covered. (88.99%)

23 existing lines in 12 files now uncovered.

10578 of 11999 relevant lines covered (88.16%)

0.88 hits per line

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

78.44
/core/mybatis-generator-core/src/main/java/org/mybatis/generator/plugins/EqualsHashCodePlugin.java
1
/*
2
 *    Copyright 2006-2025 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 classes. It demonstrates the process of
38
 * adding methods to generated classes
39
 * <p>
40
 * The <code>equals</code> method generated by this class is correct in most cases, but will probably NOT be correct if
41
 * you have specified a rootClass - because our equals method only checks the fields it knows about.
42
 * <p>
43
 * Similarly, the <code>hashCode</code> method generated by this class only relies on fields it knows about. Anything
44
 * you add, or fields in a super class will not be factored into the hash code.
45
 *
46
 * @author Jeff Butler
47
 */
48
public class EqualsHashCodePlugin extends PluginAdapter {
1✔
49

50
    private boolean useEqualsHashCodeFromRoot;
51

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

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

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

75
        generateEquals(topLevelClass, columns, introspectedTable);
1✔
76
        generateHashCode(topLevelClass, columns, introspectedTable);
1✔
77

78
        return true;
1✔
79
    }
80

81
    @Override
82
    public boolean modelPrimaryKeyClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
83
        generateEquals(topLevelClass, introspectedTable.getPrimaryKeyColumns(), introspectedTable);
1✔
84
        generateHashCode(topLevelClass, introspectedTable.getPrimaryKeyColumns(), introspectedTable);
1✔
85

86
        return true;
1✔
87
    }
88

89
    @Override
90
    public boolean modelRecordWithBLOBsClassGenerated(TopLevelClass topLevelClass,
91
            IntrospectedTable introspectedTable) {
92
        generateEquals(topLevelClass, introspectedTable.getAllColumns(), introspectedTable);
1✔
93
        generateHashCode(topLevelClass, introspectedTable.getAllColumns(), introspectedTable);
1✔
94

95
        return true;
1✔
96
    }
97

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

122
        if (introspectedTable.getTargetRuntime() == TargetRuntime.MYBATIS3_DSQL) {
1✔
123
            context.getCommentGenerator().addGeneralMethodAnnotation(method, introspectedTable,
1✔
124
                    topLevelClass.getImportedTypes());
1✔
125
        } else {
126
            context.getCommentGenerator().addGeneralMethodComment(method, introspectedTable);
1✔
127
        }
128

129
        method.addBodyLine("if (this == that) {"); //$NON-NLS-1$
1✔
130
        method.addBodyLine("return true;"); //$NON-NLS-1$
1✔
131
        method.addBodyLine("}"); //$NON-NLS-1$
1✔
132

133
        method.addBodyLine("if (that == null) {"); //$NON-NLS-1$
1✔
134
        method.addBodyLine("return false;"); //$NON-NLS-1$
1✔
135
        method.addBodyLine("}"); //$NON-NLS-1$
1✔
136

137
        method.addBodyLine("if (getClass() != that.getClass()) {"); //$NON-NLS-1$
1✔
138
        method.addBodyLine("return false;"); //$NON-NLS-1$
1✔
139
        method.addBodyLine("}"); //$NON-NLS-1$
1✔
140

141
        StringBuilder sb = new StringBuilder();
1✔
142
        sb.append(topLevelClass.getType().getShortName());
1✔
143
        sb.append(" other = ("); //$NON-NLS-1$
1✔
144
        sb.append(topLevelClass.getType().getShortName());
1✔
145
        sb.append(") that;"); //$NON-NLS-1$
1✔
146
        method.addBodyLine(sb.toString());
1✔
147

148
        if (useEqualsHashCodeFromRoot && topLevelClass.getSuperClass().isPresent()) {
1!
149
            method.addBodyLine("if (!super.equals(other)) {"); //$NON-NLS-1$
×
150
            method.addBodyLine("return false;"); //$NON-NLS-1$
×
151
            method.addBodyLine("}"); //$NON-NLS-1$
×
152
        }
153

154
        boolean first = true;
1✔
155
        Iterator<IntrospectedColumn> iter = introspectedColumns.iterator();
1✔
156
        while (iter.hasNext()) {
1✔
157
            IntrospectedColumn introspectedColumn = iter.next();
1✔
158

159
            sb.setLength(0);
1✔
160

161
            if (first) {
1✔
162
                sb.append("return ("); //$NON-NLS-1$
1✔
163
                first = false;
1✔
164
            } else {
165
                OutputUtilities.javaIndent(sb, 1);
1✔
166
                sb.append("&& ("); //$NON-NLS-1$
1✔
167
            }
168

169
            String getterMethod = getGetterMethodName(introspectedColumn.getJavaProperty(),
1✔
170
                    introspectedColumn.getFullyQualifiedJavaType());
1✔
171

172
            if (introspectedColumn.getFullyQualifiedJavaType().isPrimitive()) {
1✔
173
                sb.append("this."); //$NON-NLS-1$
1✔
174
                sb.append(getterMethod);
1✔
175
                sb.append("() == "); //$NON-NLS-1$
1✔
176
                sb.append("other."); //$NON-NLS-1$
1✔
177
                sb.append(getterMethod);
1✔
178
                sb.append("())"); //$NON-NLS-1$
1✔
179
            } else if (introspectedColumn.getFullyQualifiedJavaType().isArray()) {
1✔
180
                topLevelClass.addImportedType("java.util.Arrays"); //$NON-NLS-1$
1✔
181
                sb.append("Arrays.equals(this."); //$NON-NLS-1$
1✔
182
                sb.append(getterMethod);
1✔
183
                sb.append("(), "); //$NON-NLS-1$
1✔
184
                sb.append("other."); //$NON-NLS-1$
1✔
185
                sb.append(getterMethod);
1✔
186
                sb.append("()))"); //$NON-NLS-1$
1✔
187
            } else {
188
                sb.append("this."); //$NON-NLS-1$
1✔
189
                sb.append(getterMethod);
1✔
190
                sb.append("() == null ? other."); //$NON-NLS-1$
1✔
191
                sb.append(getterMethod);
1✔
192
                sb.append("() == null : this."); //$NON-NLS-1$
1✔
193
                sb.append(getterMethod);
1✔
194
                sb.append("().equals(other."); //$NON-NLS-1$
1✔
195
                sb.append(getterMethod);
1✔
196
                sb.append("()))"); //$NON-NLS-1$
1✔
197
            }
198

199
            if (!iter.hasNext()) {
1✔
200
                sb.append(';');
1✔
201
            }
202

203
            method.addBodyLine(sb.toString());
1✔
204
        }
1✔
205

206
        topLevelClass.addMethod(method);
1✔
207
    }
1✔
208

209
    /**
210
     * Generates a <code>hashCode</code> method that includes all fields.
211
     * <p>
212
     * Note that this implementation is based on the eclipse foundation hashCode generator.
213
     *
214
     * @param topLevelClass
215
     *            the class to which the method will be added
216
     * @param introspectedColumns
217
     *            column definitions of this class and any superclass of this class
218
     * @param introspectedTable
219
     *            the table corresponding to this class
220
     */
221
    protected void generateHashCode(TopLevelClass topLevelClass, List<IntrospectedColumn> introspectedColumns,
222
            IntrospectedTable introspectedTable) {
223
        Method method = new Method("hashCode"); //$NON-NLS-1$
1✔
224
        method.setVisibility(JavaVisibility.PUBLIC);
1✔
225
        method.setReturnType(FullyQualifiedJavaType.getIntInstance());
1✔
226
        method.addAnnotation("@Override"); //$NON-NLS-1$
1✔
227

228
        if (introspectedTable.getTargetRuntime() == TargetRuntime.MYBATIS3_DSQL) {
1✔
229
            context.getCommentGenerator().addGeneralMethodAnnotation(method, introspectedTable,
1✔
230
                    topLevelClass.getImportedTypes());
1✔
231
        } else {
232
            context.getCommentGenerator().addGeneralMethodComment(method, introspectedTable);
1✔
233
        }
234

235
        method.addBodyLine("final int prime = 31;"); //$NON-NLS-1$
1✔
236
        method.addBodyLine("int result = 1;"); //$NON-NLS-1$
1✔
237

238
        if (useEqualsHashCodeFromRoot && topLevelClass.getSuperClass().isPresent()) {
1!
239
            method.addBodyLine("result = prime * result + super.hashCode();"); //$NON-NLS-1$
×
240
        }
241

242
        StringBuilder sb = new StringBuilder();
1✔
243
        boolean hasTemp = false;
1✔
244
        for (IntrospectedColumn introspectedColumn : introspectedColumns) {
1✔
245
            FullyQualifiedJavaType fqjt = introspectedColumn.getFullyQualifiedJavaType();
1✔
246

247
            String getterMethod = getGetterMethodName(introspectedColumn.getJavaProperty(), fqjt);
1✔
248

249
            sb.setLength(0);
1✔
250
            if (fqjt.isPrimitive()) {
1✔
251
                if ("boolean".equals(fqjt.getFullyQualifiedName())) { //$NON-NLS-1$
1✔
252
                    sb.append("result = prime * result + ("); //$NON-NLS-1$
1✔
253
                    sb.append(getterMethod);
1✔
254
                    sb.append("() ? 1231 : 1237);"); //$NON-NLS-1$
1✔
255
                    method.addBodyLine(sb.toString());
1✔
256
                } else if ("byte".equals(fqjt.getFullyQualifiedName())) { //$NON-NLS-1$
1!
257
                    sb.append("result = prime * result + "); //$NON-NLS-1$
×
258
                    sb.append(getterMethod);
×
259
                    sb.append("();"); //$NON-NLS-1$
×
260
                    method.addBodyLine(sb.toString());
×
261
                } else if ("char".equals(fqjt.getFullyQualifiedName())) { //$NON-NLS-1$
1!
262
                    sb.append("result = prime * result + "); //$NON-NLS-1$
×
263
                    sb.append(getterMethod);
×
264
                    sb.append("();"); //$NON-NLS-1$
×
265
                    method.addBodyLine(sb.toString());
×
266
                } else if ("double".equals(fqjt.getFullyQualifiedName())) { //$NON-NLS-1$
1!
267
                    if (!hasTemp) {
×
268
                        method.addBodyLine("long temp;"); //$NON-NLS-1$
×
269
                        hasTemp = true;
×
270
                    }
271
                    sb.append("temp = Double.doubleToLongBits("); //$NON-NLS-1$
×
272
                    sb.append(getterMethod);
×
273
                    sb.append("());"); //$NON-NLS-1$
×
274
                    method.addBodyLine(sb.toString());
×
NEW
275
                    method.addBodyLine("result = prime * result + (int) (temp ^ (temp >>> 32));"); //$NON-NLS-1$
×
276
                } else if ("float".equals(fqjt.getFullyQualifiedName())) { //$NON-NLS-1$
1!
NEW
277
                    sb.append("result = prime * result + Float.floatToIntBits("); //$NON-NLS-1$
×
278
                    sb.append(getterMethod);
×
279
                    sb.append("());"); //$NON-NLS-1$
×
280
                    method.addBodyLine(sb.toString());
×
281
                } else if ("int".equals(fqjt.getFullyQualifiedName())) { //$NON-NLS-1$
1!
282
                    sb.append("result = prime * result + "); //$NON-NLS-1$
1✔
283
                    sb.append(getterMethod);
1✔
284
                    sb.append("();"); //$NON-NLS-1$
1✔
285
                    method.addBodyLine(sb.toString());
1✔
286
                } else if ("long".equals(fqjt.getFullyQualifiedName())) { //$NON-NLS-1$
×
287
                    sb.append("result = prime * result + (int) ("); //$NON-NLS-1$
×
288
                    sb.append(getterMethod);
×
289
                    sb.append("() ^ ("); //$NON-NLS-1$
×
290
                    sb.append(getterMethod);
×
291
                    sb.append("() >>> 32));"); //$NON-NLS-1$
×
292
                    method.addBodyLine(sb.toString());
×
293
                } else if ("short".equals(fqjt.getFullyQualifiedName())) { //$NON-NLS-1$
×
294
                    sb.append("result = prime * result + "); //$NON-NLS-1$
×
295
                    sb.append(getterMethod);
×
296
                    sb.append("();"); //$NON-NLS-1$
×
297
                    method.addBodyLine(sb.toString());
×
298
                }
299
            } else if (fqjt.isArray()) {
1✔
300
                // Arrays is already imported by the generateEquals method, we don't need
301
                // to do it again
302
                sb.append("result = prime * result + (Arrays.hashCode("); //$NON-NLS-1$
1✔
303
                sb.append(getterMethod);
1✔
304
                sb.append("()));"); //$NON-NLS-1$
1✔
305
                method.addBodyLine(sb.toString());
1✔
306
            } else {
307
                sb.append("result = prime * result + (("); //$NON-NLS-1$
1✔
308
                sb.append(getterMethod);
1✔
309
                sb.append("() == null) ? 0 : "); //$NON-NLS-1$
1✔
310
                sb.append(getterMethod);
1✔
311
                sb.append("().hashCode());"); //$NON-NLS-1$
1✔
312
                method.addBodyLine(sb.toString());
1✔
313
            }
314
        }
1✔
315

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

318
        topLevelClass.addMethod(method);
1✔
319
    }
1✔
320
}
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

© 2025 Coveralls, Inc