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

hazendaz / javabean-tester / 3227

16 Feb 2026 12:20AM UTC coverage: 87.5% (-0.4%) from 87.852%
3227

push

github

hazendaz
Found possible bug in handling, its not always possible to be purist on current code for equals

noted what the expectation was, its not achieved, so just allow it through.  This was an existing problem that the tests didn't catch due to sub objects.  I had added a test when looking at lombok builder pattern and stumbled onto it.  In the equals only tests, its actually doing almost same thing.  This area is known not strong enough and is additionally using equals verifier to try to compensate.

285 of 331 branches covered (86.1%)

5 of 5 new or added lines in 1 file covered. (100.0%)

67 existing lines in 6 files now uncovered.

525 of 600 relevant lines covered (87.5%)

0.88 hits per line

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

96.15
/src/main/java/com/codebox/builders/ExtensionBuilder.java
1
/*
2
 * SPDX-License-Identifier: Apache-2.0
3
 * See LICENSE file for details.
4
 *
5
 * Copyright 2012-2026 hazendaz
6
 *
7
 * Portions of initial baseline code (getter/setter test) by Rob Dawson (CodeBox)
8
 */
9
package com.codebox.builders;
10

11
import java.util.HashMap;
12
import java.util.Map;
13
import java.util.Map.Entry;
14
import javassist.CannotCompileException;
15
import javassist.ClassPool;
16
import javassist.CtClass;
17
import javassist.CtField;
18
import javassist.CtMethod;
19
import javassist.NotFoundException;
20

21
import org.slf4j.Logger;
22
import org.slf4j.LoggerFactory;
23

24
/**
25
 * ExtensionBuilder dynamically generates a subclass of the given class with additional String properties and their
26
 * getters/setters.
27
 * <p>
28
 * Uses Javassist to create a new class at runtime named <code>clazz.getName() + "Extension"</code>. The generated class
29
 * will have four String properties: jbExtension1, jbExtension2, jbExtension3, jbExtension4.
30
 *
31
 * @param <T>
32
 *            the type to extend
33
 */
34
public class ExtensionBuilder<T> {
1✔
35

36
    /** The Constant logger. */
37
    private static final Logger logger = LoggerFactory.getLogger(ExtensionBuilder.class);
1✔
38

39
    /**
40
     * Generates a dynamic subclass of the given class with additional String properties and their getters/setters.
41
     *
42
     * @param clazz
43
     *            the class to extend
44
     * @return the generated class
45
     * @throws NotFoundException
46
     *             if the class cannot be found in the class pool
47
     * @throws CannotCompileException
48
     *             if the class cannot be compiled
49
     */
50
    public Class<?> generate(final Class<T> clazz) throws NotFoundException, CannotCompileException {
51
        try {
52
            // If extension already recreated, return it
UNCOV
53
            return Class.forName(clazz.getName() + "Extension");
×
54
        } catch (final ClassNotFoundException e) {
1✔
55
            // No extension exists, so create it
56
            ExtensionBuilder.logger.trace("No extension exists, so create it", e);
1✔
57
        }
58

59
        final ClassPool pool = ClassPool.getDefault();
1✔
60
        final CtClass cc = pool.makeClass(clazz.getName() + "Extension");
1✔
61

62
        // add super class
63
        cc.setSuperclass(ExtensionBuilder.resolveCtClass(clazz));
1✔
64

65
        final Map<String, Class<?>> properties = new HashMap<>();
1✔
66
        properties.put("jbExtension1", String.class);
1✔
67
        properties.put("jbExtension2", String.class);
1✔
68
        properties.put("jbExtension3", String.class);
1✔
69
        properties.put("jbExtension4", String.class);
1✔
70

71
        for (final Entry<String, Class<?>> entry : properties.entrySet()) {
1✔
72

73
            // Add field
74
            cc.addField(new CtField(ExtensionBuilder.resolveCtClass(entry.getValue()), entry.getKey(), cc));
1✔
75

76
            // Add getter
77
            cc.addMethod(ExtensionBuilder.generateGetter(cc, entry.getKey(), entry.getValue()));
1✔
78

79
            // Add setter
80
            cc.addMethod(ExtensionBuilder.generateSetter(cc, entry.getKey(), entry.getValue()));
1✔
81
        }
1✔
82

83
        return cc.toClass();
1✔
84
    }
85

86
    /**
87
     * Generates a getter method for the specified field.
88
     *
89
     * @param declaringClass
90
     *            the class to add the method to
91
     * @param fieldName
92
     *            the name of the field
93
     * @param fieldClass
94
     *            the type of the field
95
     * @return the generated getter method
96
     * @throws CannotCompileException
97
     *             if the method cannot be compiled
98
     */
99
    private static CtMethod generateGetter(final CtClass declaringClass, final String fieldName,
100
            final Class<?> fieldClass) throws CannotCompileException {
101
        String methodSrc = """
1✔
102
                public %s get%s() {
103
                    return this.%s;
104
                }
105
                """.formatted(fieldClass.getName(), fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1),
1✔
106
                fieldName);
107
        return CtMethod.make(methodSrc, declaringClass);
1✔
108
    }
109

110
    /**
111
     * Generates a setter method for the specified field.
112
     *
113
     * @param declaringClass
114
     *            the class to add the method to
115
     * @param fieldName
116
     *            the name of the field
117
     * @param fieldClass
118
     *            the type of the field
119
     * @return the generated setter method
120
     * @throws CannotCompileException
121
     *             if the method cannot be compiled
122
     */
123
    private static CtMethod generateSetter(final CtClass declaringClass, final String fieldName,
124
            final Class<?> fieldClass) throws CannotCompileException {
125
        String methodSrc = """
1✔
126
                public void set%s(%s %s) {
127
                    this.%s = %s;
128
                }
129
                """.formatted(fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1), fieldClass.getName(),
1✔
130
                fieldName, fieldName, fieldName);
131
        return CtMethod.make(methodSrc, declaringClass);
1✔
132
    }
133

134
    /**
135
     * Resolves a CtClass from a Java Class using the default class pool.
136
     *
137
     * @param clazz
138
     *            the Java class to resolve
139
     * @return the corresponding CtClass
140
     * @throws NotFoundException
141
     *             if the class cannot be found in the class pool
142
     */
143
    private static CtClass resolveCtClass(final Class<?> clazz) throws NotFoundException {
144
        return ClassPool.getDefault().get(clazz.getName());
1✔
145
    }
146

147
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc