• 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

71.19
/src/main/java/com/codebox/bean/ByteBuddyBeanCopier.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.bean;
10

11
import java.lang.reflect.Method;
12
import java.util.HashMap;
13
import java.util.Map;
14

15
/**
16
 * The Class ByteBuddyBeanCopier.
17
 */
18
public final class ByteBuddyBeanCopier {
19

20
    /**
21
     * Instantiates a new byte buddy bean copier.
22
     */
UNCOV
23
    private ByteBuddyBeanCopier() {
×
UNCOV
24
        throw new AssertionError("Utility class should not be instantiated");
×
25
    }
26

27
    /**
28
     * Copy.
29
     *
30
     * @param source
31
     *            the source
32
     * @param target
33
     *            the target
34
     * @param converter
35
     *            the converter
36
     */
37
    public static void copy(Object source, Object target, BooleanConverter converter) {
38
        if (source == null || target == null) {
1✔
39
            return;
1✔
40
        }
41

42
        Class<?> clazz = source.getClass();
1✔
43
        Map<String, Method> getters = new HashMap<>();
1✔
44
        Map<String, Method> setters = new HashMap<>();
1✔
45

46
        for (Method method : clazz.getMethods()) {
1✔
47
            if (ByteBuddyBeanCopier.isGetter(method)) {
1✔
48
                String property = ByteBuddyBeanCopier.decapitalize(ByteBuddyBeanCopier.extractPropertyName(method));
1✔
49
                getters.put(property, method);
1✔
50
            } else if (ByteBuddyBeanCopier.isSetter(method)) {
1✔
51
                String property = ByteBuddyBeanCopier.decapitalize(method.getName().substring(3));
1✔
52
                setters.put(property, method);
1✔
53
            }
54
        }
55

56
        for (Map.Entry<String, Method> entry : setters.entrySet()) {
1✔
57
            String property = entry.getKey();
1✔
58
            Method setter = entry.getValue();
1✔
59
            Method getter = getters.get(property);
1✔
60

61
            try {
62
                Object value = null;
1✔
63
                if (getter != null) {
1!
64
                    value = getter.invoke(source);
1✔
UNCOV
65
                } else if (isBooleanType(setter.getParameterTypes()[0])) {
×
66
                    // Try 'is' method for Boolean if getter is missing
UNCOV
67
                    String isMethodName = "is" + ByteBuddyBeanCopier.capitalize(property);
×
68
                    try {
UNCOV
69
                        Method isMethod = clazz.getMethod(isMethodName);
×
UNCOV
70
                        if (isBooleanType(isMethod.getReturnType())) {
×
71
                            value = isMethod.invoke(source);
×
72
                        }
73
                    } catch (NoSuchMethodException ignored) {
×
74
                        // No 'is' method, skip
75
                    }
×
76
                }
77
                if (converter != null && isBooleanType(setter.getParameterTypes()[0])) {
1!
78
                    value = converter.convert(value, setter.getParameterTypes()[0]);
1✔
79
                }
80
                if (value != null || !setter.getParameterTypes()[0].isPrimitive()) {
1!
81
                    setter.invoke(target, value);
1✔
82
                }
UNCOV
83
            } catch (Exception e) {
×
UNCOV
84
                throw new RuntimeException("Failed to copy property: " + property, e);
×
85
            }
1✔
86
        }
1✔
87
    }
1✔
88

89
    /**
90
     * Checks if is getter.
91
     *
92
     * @param method
93
     *            the method
94
     * @return true, if is getter
95
     */
96
    private static boolean isGetter(Method method) {
97
        if (method.getParameterCount() != 0) {
1✔
98
            return false;
1✔
99
        }
100
        String name = method.getName();
1✔
101
        return name.startsWith("get") && !method.getReturnType().equals(void.class) && name.length() > 3
1!
102
                || name.startsWith("is") && isBooleanType(method.getReturnType()) && name.length() > 2;
1!
103
    }
104

105
    /**
106
     * Checks if is setter.
107
     *
108
     * @param method
109
     *            the method
110
     * @return true, if is setter
111
     */
112
    private static boolean isSetter(Method method) {
113
        return method.getName().startsWith("set") && method.getParameterCount() == 1
1!
114
                && method.getReturnType().equals(void.class);
1!
115
    }
116

117
    /**
118
     * Checks if is boolean type.
119
     *
120
     * @param type
121
     *            the type
122
     * @return true, if is boolean type
123
     */
124
    private static boolean isBooleanType(Class<?> type) {
125
        return type == boolean.class || type == Boolean.class;
1✔
126
    }
127

128
    /**
129
     * Extract property name.
130
     *
131
     * @param getter
132
     *            the getter
133
     * @return the string
134
     */
135
    private static String extractPropertyName(Method getter) {
136
        String name = getter.getName();
1✔
137
        if (name.startsWith("get")) {
1✔
138
            return name.substring(3);
1✔
139
        }
140
        if (name.startsWith("is")) {
1!
141
            return name.substring(2);
1✔
142
        }
UNCOV
143
        throw new IllegalArgumentException("Not a getter method: " + name);
×
144
    }
145

146
    /**
147
     * Decapitalize.
148
     *
149
     * @param name
150
     *            the name
151
     * @return the string
152
     */
153
    private static String decapitalize(String name) {
154
        if (name == null || name.isEmpty()) {
1!
UNCOV
155
            return name;
×
156
        }
157
        if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) && Character.isUpperCase(name.charAt(0))) {
1!
UNCOV
158
            return name;
×
159
        }
160
        return Character.toLowerCase(name.charAt(0)) + name.substring(1);
1✔
161
    }
162

163
    /**
164
     * Capitalize.
165
     *
166
     * @param name
167
     *            the name
168
     * @return the string
169
     */
170
    private static String capitalize(String name) {
UNCOV
171
        if (name == null || name.isEmpty()) {
×
UNCOV
172
            return name;
×
173
        }
UNCOV
174
        return Character.toUpperCase(name.charAt(0)) + name.substring(1);
×
175
    }
176

177
    /**
178
     * The Interface BooleanConverter.
179
     */
180
    public interface BooleanConverter {
181

182
        /**
183
         * Convert.
184
         *
185
         * @param value
186
         *            the value
187
         * @param targetType
188
         *            the target type
189
         * @return the object
190
         */
191
        Object convert(Object value, Class<?> targetType);
192
    }
193

194
}
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