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

aspectran / aspectran / #4075

19 Feb 2025 12:58PM CUT coverage: 35.181% (-0.004%) from 35.185%
#4075

push

github

topframe
Update

20 of 155 new or added lines in 9 files covered. (12.9%)

5 existing lines in 3 files now uncovered.

14252 of 40510 relevant lines covered (35.18%)

0.35 hits per line

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

0.0
/utils/src/main/java/com/aspectran/utils/BeanTypeUtils.java
1
/*
2
 * Copyright (c) 2008-2025 The Aspectran Project
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
 *     http://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 com.aspectran.utils;
17

18
import com.aspectran.utils.annotation.jsr305.NonNull;
19

20
import java.lang.reflect.InvocationTargetException;
21
import java.lang.reflect.Method;
22
import java.lang.reflect.Modifier;
23
import java.util.List;
24
import java.util.Map;
25
import java.util.Properties;
26
import java.util.StringTokenizer;
27

28
import static com.aspectran.utils.BeanUtils.NO_ARGUMENTS;
29

30
/**
31
 * BeanTypeUtils provides methods that allow simple, reflective access to
32
 * JavaBeans style properties. Methods are provided for all simple types.
33
 * This has been decoupled from BeanUtils.
34
 *
35
 * <p>Created: 2025-02-19</p>
36
 */
NEW
37
public abstract class BeanTypeUtils {
×
38

39
    /**
40
     * Invokes the static method of the specified class to get the bean property value.
41
     * @param type the class for which to lookup
42
     * @param name the property name
43
     * @return the property value (as an Object)
44
     * @throws InvocationTargetException if the property accessor method throws an exception
45
     */
46
    public static Object getProperty(Class<?> type, String name) throws InvocationTargetException {
47
        try {
NEW
48
            BeanDescriptor bd = BeanDescriptor.getInstance(type);
×
NEW
49
            Method method = bd.getGetter(name);
×
NEW
50
            Object bean = null;
×
NEW
51
            if (!Modifier.isStatic(method.getModifiers())) {
×
NEW
52
                bean = ClassUtils.createInstance(type);
×
53
            }
54
            try {
NEW
55
                return method.invoke(bean, NO_ARGUMENTS);
×
NEW
56
            } catch (Throwable t) {
×
NEW
57
                throw ExceptionUtils.unwrapThrowable(t);
×
58
            }
NEW
59
        } catch (InvocationTargetException e) {
×
NEW
60
            throw e;
×
NEW
61
        } catch (Throwable t) {
×
NEW
62
            throw new InvocationTargetException(t, "Could not get property '" + name +
×
NEW
63
                    "' from " + type.getName() + ". Cause: " + t);
×
64
        }
65
    }
66

67
    /**
68
     * Invokes the static method of the specified class to get the bean property value.
69
     * @param type the class for which to lookup
70
     * @param name the property name
71
     * @param value the value to which this property is to be set
72
     * @throws InvocationTargetException if the property accessor method throws an exception
73
     */
74
    public static void setProperty(Class<?> type, String name, Object value) throws InvocationTargetException {
NEW
75
        Object bean = null;
×
76
        try {
NEW
77
            BeanDescriptor bd = BeanDescriptor.getInstance(type);
×
NEW
78
            Method method = bd.getSetter(name);
×
NEW
79
            Object[] params = new Object[] { value };
×
NEW
80
            if (!Modifier.isStatic(method.getModifiers())) {
×
NEW
81
                bean = ClassUtils.createInstance(type);
×
82
            }
83
            try {
NEW
84
                method.invoke(bean, params);
×
NEW
85
            } catch (Throwable t) {
×
NEW
86
                throw ExceptionUtils.unwrapThrowable(t);
×
NEW
87
            }
×
NEW
88
        } catch (InvocationTargetException e) {
×
NEW
89
            throw e;
×
NEW
90
        } catch (Throwable t) {
×
91
            try {
NEW
92
                if (bean != null) {
×
NEW
93
                    MethodUtils.invokeSetter(bean, name, value);
×
94
                } else {
NEW
95
                    MethodUtils.invokeStaticMethod(type, name, value);
×
96
                }
NEW
97
                return;
×
NEW
98
            } catch (Throwable tt) {
×
99
                //ignore
100
            }
NEW
101
            throw new InvocationTargetException(t, "Could not set property '" + name +
×
NEW
102
                    "' to value '" + value + "' for " + type.getName() + ". Cause: " + t);
×
NEW
103
        }
×
NEW
104
    }
×
105

106
    /**
107
     * Returns the class that the getter will return when reading a property value.
108
     * @param bean the bean to check
109
     * @param name the name of the property
110
     * @return the type of the property
111
     * @throws NoSuchMethodException if an accessor method for this property cannot be found
112
     */
113
    public static Class<?> getPropertyTypeForGetter(@NonNull Object bean, String name) throws NoSuchMethodException {
114
        Class<?> type;
NEW
115
        if (bean instanceof Class<?> beanClass) {
×
NEW
116
            type = getClassPropertyTypeForGetter(beanClass, name);
×
NEW
117
        } else if (bean instanceof Map<?, ?> map) {
×
NEW
118
            type = getPropertyType(map, name);
×
119
        } else {
NEW
120
            type = getClassPropertyTypeForGetter(bean.getClass(), name);
×
121
        }
NEW
122
        return type;
×
123
    }
124

125
    /**
126
     * Returns the class that the getter will return when reading a property value.
127
     * @param type the class to check
128
     * @param name the name of the property
129
     * @return the type of the property
130
     * @throws NoSuchMethodException if an accessor method for this property cannot be found
131
     */
132
    public static Class<?> getClassPropertyTypeForGetter(Class<?> type, @NonNull String name)
133
            throws NoSuchMethodException {
NEW
134
        if (name.contains(".")) {
×
NEW
135
            StringTokenizer parser = new StringTokenizer(name, ".");
×
NEW
136
            while (parser.hasMoreTokens()) {
×
NEW
137
                name = parser.nextToken();
×
NEW
138
                type = BeanDescriptor.getInstance(type).getGetterType(name);
×
139
            }
NEW
140
        } else {
×
NEW
141
            type = BeanDescriptor.getInstance(type).getGetterType(name);
×
142
        }
NEW
143
        return type;
×
144
    }
145

146
    /**
147
     * Returns the class that the setter expects to receive as a parameter when
148
     * setting a property value.
149
     * @param bean the bean to check
150
     * @param name the name of the property
151
     * @return the type of the property
152
     * @throws NoSuchMethodException if an accessor method for this property cannot be found
153
     */
154
    public static Class<?> getPropertyTypeForSetter(@NonNull Object bean, String name) throws NoSuchMethodException {
155
        Class<?> type;
NEW
156
        if (bean instanceof Class<?> beanClass) {
×
NEW
157
            type = getClassPropertyTypeForSetter(beanClass, name);
×
NEW
158
        } else if (bean instanceof Map<?, ?> map) {
×
NEW
159
            type = getPropertyType(map, name);
×
160
        } else {
NEW
161
            type = getPropertyTypeForSetter(bean.getClass(), name);
×
162
        }
NEW
163
        return type;
×
164
    }
165

166
    /**
167
     * Returns the class that the setter expects to receive as a parameter when
168
     * setting a property value.
169
     * @param type The class to check
170
     * @param name the name of the property
171
     * @return the type of the property
172
     * @throws NoSuchMethodException if an accessor method for this property cannot be found
173
     */
174
    public static Class<?> getClassPropertyTypeForSetter(Class<?> type, @NonNull String name)
175
            throws NoSuchMethodException {
NEW
176
        if (name.contains(".")) {
×
NEW
177
            StringTokenizer parser = new StringTokenizer(name, ".");
×
NEW
178
            while (parser.hasMoreTokens()) {
×
NEW
179
                name = parser.nextToken();
×
NEW
180
                type = BeanDescriptor.getInstance(type).getSetterType(name);
×
181
            }
NEW
182
        } else {
×
NEW
183
            type = BeanDescriptor.getInstance(type).getSetterType(name);
×
184
        }
NEW
185
        return type;
×
186
    }
187

188
    private static Class<?> getPropertyType(@NonNull Map<?, ?> map, String name) {
NEW
189
        Object value = map.get(name);
×
NEW
190
        if (value == null && map instanceof Properties props) {
×
191
            // Allow for defaults fallback or potentially overridden accessor...
NEW
192
            value = props.getProperty(name);
×
193
        }
194
        Class<?> type;
NEW
195
        if (value == null) {
×
NEW
196
            type = Object.class;
×
197
        } else {
NEW
198
            type = value.getClass();
×
199
        }
NEW
200
        return type;
×
201
    }
202

203
    public static Class<?> getIndexedType(Object bean, @NonNull String indexedName) throws InvocationTargetException {
204
        try {
NEW
205
            String name = indexedName.substring(0, indexedName.indexOf("["));
×
NEW
206
            int i = Integer.parseInt(indexedName.substring(indexedName.indexOf("[") + 1, indexedName.indexOf("]")));
×
NEW
207
            Object obj = (!name.isEmpty() ? BeanUtils.getSimpleProperty(bean, name) : bean);
×
208
            Class<?> value;
NEW
209
            if (obj instanceof List<?> list) {
×
NEW
210
                value = list.get(i).getClass();
×
NEW
211
            } else if (obj instanceof Object[] arr) {
×
NEW
212
                value = arr[i].getClass();
×
NEW
213
            } else if (obj instanceof char[]) {
×
NEW
214
                value = Character.class;
×
NEW
215
            } else if (obj instanceof boolean[]) {
×
NEW
216
                value = Boolean.class;
×
NEW
217
            } else if (obj instanceof byte[]) {
×
NEW
218
                value = Byte.class;
×
NEW
219
            } else if (obj instanceof double[]) {
×
NEW
220
                value = Double.class;
×
NEW
221
            } else if (obj instanceof float[]) {
×
NEW
222
                value = Float.class;
×
NEW
223
            } else if (obj instanceof int[]) {
×
NEW
224
                value = Integer.class;
×
NEW
225
            } else if (obj instanceof long[]) {
×
NEW
226
                value = Long.class;
×
NEW
227
            } else if (obj instanceof short[]) {
×
NEW
228
                value = Short.class;
×
229
            } else {
NEW
230
                throw new IllegalArgumentException("The '" + name + "' property of the " +
×
NEW
231
                        bean.getClass().getName() + " class is not a List or Array");
×
232
            }
NEW
233
            return value;
×
NEW
234
        } catch (InvocationTargetException e) {
×
NEW
235
            throw e;
×
NEW
236
        } catch (Exception e) {
×
NEW
237
            throw new InvocationTargetException(e, "Error getting ordinal list from JavaBean. Cause: " + e);
×
238
        }
239
    }
240

241
    public static boolean hasReadableProperty(Class<?> type, String name) {
242
        try {
NEW
243
            BeanDescriptor bd = BeanDescriptor.getInstance(type);
×
NEW
244
            bd.getGetter(name);
×
NEW
245
            return true;
×
NEW
246
        } catch (Throwable t) {
×
NEW
247
            return false;
×
248
        }
249
    }
250

251
    public static boolean hasWritableProperty(Class<?> type, String name) {
252
        try {
NEW
253
            BeanDescriptor bd = BeanDescriptor.getInstance(type);
×
NEW
254
            bd.getSetter(name);
×
NEW
255
            return true;
×
NEW
256
        } catch (Throwable t) {
×
NEW
257
            return false;
×
258
        }
259
    }
260

261
    public static boolean hasStaticReadableProperty(Class<?> type, String name) {
262
        try {
NEW
263
            BeanDescriptor bd = BeanDescriptor.getInstance(type);
×
NEW
264
            Method method = bd.getGetter(name);
×
NEW
265
            return Modifier.isStatic(method.getModifiers());
×
NEW
266
        } catch (Throwable t) {
×
NEW
267
            return false;
×
268
        }
269
    }
270

271
    public static boolean hasStaticWritableProperty(Class<?> type, String name) {
272
        try {
NEW
273
            BeanDescriptor bd = BeanDescriptor.getInstance(type);
×
NEW
274
            Method method = bd.getSetter(name);
×
NEW
275
            return Modifier.isStatic(method.getModifiers());
×
NEW
276
        } catch (Throwable t) {
×
NEW
277
            return false;
×
278
        }
279
    }
280

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