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

hazendaz / javabean-tester / 2736

29 Jun 2025 11:13PM UTC coverage: 86.972% (-2.5%) from 89.452%
2736

push

github

hazendaz
Remove asm/cglib replacing logic with byte buddy in mostly compliant way to how cglib worked

269 of 319 branches covered (84.33%)

62 of 84 new or added lines in 3 files covered. (73.81%)

4 existing lines in 1 file now uncovered.

494 of 568 relevant lines covered (86.97%)

0.87 hits per line

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

69.49
/src/main/java/com/codebox/bean/ByteBuddyBeanCopier.java
1
/*
2
 * JavaBean Tester (https://github.com/hazendaz/javabean-tester)
3
 *
4
 * Copyright 2012-2025 Hazendaz.
5
 *
6
 * All rights reserved. This program and the accompanying materials
7
 * are made available under the terms of The Apache Software License,
8
 * Version 2.0 which accompanies this distribution, and is available at
9
 * http://www.apache.org/licenses/LICENSE-2.0.txt
10
 *
11
 * Contributors:
12
 *     CodeBox (Rob Dawson).
13
 *     Hazendaz (Jeremy Landis).
14
 */
15
package com.codebox.bean;
16

17
import java.lang.reflect.Method;
18
import java.util.HashMap;
19
import java.util.Map;
20

21
/**
22
 * The Class ByteBuddyBeanCopier.
23
 */
24
public final class ByteBuddyBeanCopier {
25

26
    /**
27
     * Instantiates a new byte buddy bean copier.
28
     */
NEW
29
    private ByteBuddyBeanCopier() {
×
NEW
30
        throw new AssertionError("Utility class should not be instantiated");
×
31
    }
32

33
    /**
34
     * Copy.
35
     *
36
     * @param source
37
     *            the source
38
     * @param target
39
     *            the target
40
     * @param converter
41
     *            the converter
42
     */
43
    public static void copy(Object source, Object target, BooleanConverter converter) {
44
        if (source == null || target == null) {
1!
NEW
45
            return;
×
46
        }
47

48
        Class<?> clazz = source.getClass();
1✔
49
        Map<String, Method> getters = new HashMap<>();
1✔
50
        Map<String, Method> setters = new HashMap<>();
1✔
51

52
        for (Method method : clazz.getMethods()) {
1✔
53
            if (ByteBuddyBeanCopier.isGetter(method)) {
1✔
54
                String property = ByteBuddyBeanCopier.decapitalize(ByteBuddyBeanCopier.extractPropertyName(method));
1✔
55
                getters.put(property, method);
1✔
56
            } else if (ByteBuddyBeanCopier.isSetter(method)) {
1✔
57
                String property = ByteBuddyBeanCopier.decapitalize(method.getName().substring(3));
1✔
58
                setters.put(property, method);
1✔
59
            }
60
        }
61

62
        for (Map.Entry<String, Method> entry : setters.entrySet()) {
1✔
63
            String property = entry.getKey();
1✔
64
            Method setter = entry.getValue();
1✔
65
            Method getter = getters.get(property);
1✔
66

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

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

111
    /**
112
     * Checks if is setter.
113
     *
114
     * @param method
115
     *            the method
116
     * @return true, if is setter
117
     */
118
    private static boolean isSetter(Method method) {
119
        return method.getName().startsWith("set") && method.getParameterCount() == 1
1!
120
                && method.getReturnType().equals(void.class);
1!
121
    }
122

123
    /**
124
     * Checks if is boolean type.
125
     *
126
     * @param type
127
     *            the type
128
     * @return true, if is boolean type
129
     */
130
    private static boolean isBooleanType(Class<?> type) {
131
        return type == boolean.class || type == Boolean.class;
1✔
132
    }
133

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

152
    /**
153
     * Decapitalize.
154
     *
155
     * @param name
156
     *            the name
157
     * @return the string
158
     */
159
    private static String decapitalize(String name) {
160
        if (name == null || name.isEmpty()) {
1!
NEW
161
            return name;
×
162
        }
163
        if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) && Character.isUpperCase(name.charAt(0))) {
1!
NEW
164
            return name;
×
165
        }
166
        return Character.toLowerCase(name.charAt(0)) + name.substring(1);
1✔
167
    }
168

169
    /**
170
     * Capitalize.
171
     *
172
     * @param name
173
     *            the name
174
     * @return the string
175
     */
176
    private static String capitalize(String name) {
NEW
177
        if (name == null || name.isEmpty()) {
×
NEW
178
            return name;
×
179
        }
NEW
180
        return Character.toUpperCase(name.charAt(0)) + name.substring(1);
×
181
    }
182

183
    /**
184
     * The Interface BooleanConverter.
185
     */
186
    public interface BooleanConverter {
187

188
        /**
189
         * Convert.
190
         *
191
         * @param value
192
         *            the value
193
         * @param targetType
194
         *            the target type
195
         * @return the object
196
         */
197
        Object convert(Object value, Class<?> targetType);
198
    }
199

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