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

hazendaz / httpunit / 656

06 Dec 2025 09:11PM UTC coverage: 80.452% (+0.02%) from 80.435%
656

push

github

hazendaz
[maven-release-plugin] prepare for next development iteration

3213 of 4105 branches covered (78.27%)

Branch coverage included in aggregate %.

8245 of 10137 relevant lines covered (81.34%)

0.81 hits per line

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

72.11
/src/main/java/com/meterware/httpunit/dom/ScriptingSupport.java
1
/*
2
 * MIT License
3
 *
4
 * Copyright 2011-2025 Russell Gold
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
7
 * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
8
 * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
9
 * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10
 *
11
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions
12
 * of the Software.
13
 *
14
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
15
 * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
17
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
18
 * DEALINGS IN THE SOFTWARE.
19
 */
20
package com.meterware.httpunit.dom;
21

22
import java.lang.reflect.InvocationTargetException;
23
import java.lang.reflect.Method;
24
import java.util.Hashtable;
25

26
import org.mozilla.javascript.FunctionObject;
27
import org.mozilla.javascript.Scriptable;
28

29
/**
30
 * Utilities to support scripting.
31
 */
32
class ScriptingSupport {
×
33

34
    /** A non-null method value to be used to indicate that we have already looked up and failed to find one. **/
35
    private static final Method NO_SUCH_PROPERTY = ScriptingSupport.class.getDeclaredMethods()[0];
1✔
36

37
    /** The Constant NO_ARGS. */
38
    private static final Object[] NO_ARGS = {};
1✔
39

40
    /** map of classes to maps of string to function objects. **/
41
    private static Hashtable _classFunctionMaps = new Hashtable<>();
1✔
42

43
    /** map of classes to maps of string to getter methods. **/
44
    private static Hashtable _classGetterMaps = new Hashtable<>();
1✔
45

46
    /** map of classes to maps of string to setter methods. **/
47
    private static Hashtable _classSetterMaps = new Hashtable<>();
1✔
48

49
    /**
50
     * Checks for named property.
51
     *
52
     * @param element
53
     *            the element
54
     * @param javaPropertyName
55
     *            the java property name
56
     * @param scriptable
57
     *            the scriptable
58
     *
59
     * @return true, if successful
60
     */
61
    static boolean hasNamedProperty(Object element, String javaPropertyName, Scriptable scriptable) {
62
        Method getter = getPropertyGetter(element.getClass(), javaPropertyName);
1✔
63
        if (getter != NO_SUCH_PROPERTY) {
1!
64
            return true;
1✔
65
        }
66
        Object function = getFunctionObject(element.getClass(), javaPropertyName, scriptable);
×
67
        return function != null;
×
68
    }
69

70
    /**
71
     * Gets the named property.
72
     *
73
     * @param element
74
     *            the element
75
     * @param javaPropertyName
76
     *            the java property name
77
     * @param scriptable
78
     *            the scriptable
79
     *
80
     * @return the named property
81
     */
82
    static Object getNamedProperty(Object element, String javaPropertyName, Scriptable scriptable) {
83
        Method getter = getPropertyGetter(element.getClass(), javaPropertyName);
1✔
84
        if (getter == NO_SUCH_PROPERTY) {
1✔
85
            Object function = getFunctionObject(element.getClass(), javaPropertyName, scriptable);
1✔
86
            return function == null ? Scriptable.NOT_FOUND : function;
1✔
87
        }
88
        try {
89
            return getter.invoke(element, NO_ARGS);
1✔
90
        } catch (IllegalAccessException | InvocationTargetException e) {
×
91
            return Scriptable.NOT_FOUND;
×
92
        }
93
    }
94

95
    /**
96
     * Gets the function object.
97
     *
98
     * @param aClass
99
     *            the a class
100
     * @param methodName
101
     *            the method name
102
     * @param scriptable
103
     *            the scriptable
104
     *
105
     * @return the function object
106
     */
107
    private static FunctionObject getFunctionObject(Class aClass, String methodName, Scriptable scriptable) {
108
        Hashtable functionMap = (Hashtable) _classFunctionMaps.get(aClass);
1✔
109
        if (functionMap == null) {
1✔
110
            _classFunctionMaps.put(aClass, functionMap = new Hashtable<>());
1✔
111
        }
112

113
        Object result = functionMap.get(methodName);
1✔
114
        if (result == NO_SUCH_PROPERTY) {
1✔
115
            return null;
1✔
116
        }
117
        if (result != null) {
1!
118
            return (FunctionObject) result;
×
119
        }
120

121
        Method[] methods = aClass.getMethods();
1✔
122
        for (Method method : methods) {
1✔
123
            if (method.getName().equalsIgnoreCase(methodName)) {
1✔
124
                FunctionObject function = new FunctionObject(methodName, method, scriptable);
1✔
125
                functionMap.put(methodName, function);
1✔
126
                return function;
1✔
127
            }
128
        }
129
        functionMap.put(methodName, NO_SUCH_PROPERTY);
1✔
130
        return null;
1✔
131
    }
132

133
    /**
134
     * Gets the property getter.
135
     *
136
     * @param aClass
137
     *            the a class
138
     * @param propertyName
139
     *            the property name
140
     *
141
     * @return the property getter
142
     */
143
    private static Method getPropertyGetter(Class aClass, String propertyName) {
144
        Hashtable methodMap = (Hashtable) _classGetterMaps.get(aClass);
1✔
145
        if (methodMap == null) {
1✔
146
            _classGetterMaps.put(aClass, methodMap = new Hashtable<>());
1✔
147
        }
148

149
        Method result = (Method) methodMap.get(propertyName);
1✔
150
        if (result != null) {
1✔
151
            return result;
1✔
152
        }
153

154
        Method[] methods = aClass.getMethods();
1✔
155
        for (Method method : methods) {
1✔
156
            if (method.getParameterTypes().length > 0) {
1✔
157
                continue;
1✔
158
            }
159
            if (method.getName().equalsIgnoreCase("is" + propertyName)
1!
160
                    || method.getName().equalsIgnoreCase("get" + propertyName)) {
1✔
161
                methodMap.put(propertyName, method);
1✔
162
                return method;
1✔
163
            }
164
        }
165
        methodMap.put(propertyName, NO_SUCH_PROPERTY);
1✔
166
        return NO_SUCH_PROPERTY;
1✔
167
    }
168

169
    /**
170
     * Sets the named property.
171
     *
172
     * @param element
173
     *            the element
174
     * @param javaPropertyName
175
     *            the java property name
176
     * @param value
177
     *            the value
178
     */
179
    static void setNamedProperty(AbstractDomComponent element, String javaPropertyName, Object value) {
180
        Method setter = getPropertySetter(element.getClass(), javaPropertyName, value);
1✔
181
        if (setter == NO_SUCH_PROPERTY) {
1!
182
            return;
×
183
        }
184

185
        try {
186
            setter.invoke(element, adjustedForSetter(value, setter));
1✔
187
        } catch (IllegalAccessException | InvocationTargetException e) { /* do nothing */
×
188
        }
1✔
189
    }
1✔
190

191
    /**
192
     * Adjusted for setter.
193
     *
194
     * @param value
195
     *            the value
196
     * @param setter
197
     *            the setter
198
     *
199
     * @return the object
200
     */
201
    private static Object adjustedForSetter(Object value, Method setter) {
202
        if (value == null) {
1!
203
            return null;
×
204
        }
205
        Class targetValueClass = setter.getParameterTypes()[0];
1✔
206
        if (targetValueClass.equals(String.class)) {
1✔
207
            return value.toString();
1✔
208
        }
209
        if (!(value instanceof Number) || !isNumericParameter(targetValueClass)) {
1!
210
            return value;
×
211
        }
212

213
        if (targetValueClass.getName().equals("int")) {
1!
214
            return Integer.valueOf(((Number) value).intValue());
1✔
215
        }
216
        if (targetValueClass.getName().equals("byte")) {
×
217
            return Byte.valueOf(((Number) value).byteValue());
×
218
        }
219
        if (targetValueClass.getName().equals("long")) {
×
220
            return Long.valueOf(((Number) value).longValue());
×
221
        }
222
        if (targetValueClass.getName().equals("short")) {
×
223
            return Short.valueOf(((Number) value).shortValue());
×
224
        }
225
        if (targetValueClass.getName().equals("float")) {
×
226
            return Float.valueOf(((Number) value).intValue());
×
227
        }
228
        if (targetValueClass.getName().equals("double")) {
×
229
            return Double.valueOf(((Number) value).intValue());
×
230
        }
231
        return value;
×
232
    }
233

234
    /**
235
     * Gets the property setter.
236
     *
237
     * @param aClass
238
     *            the a class
239
     * @param propertyName
240
     *            the property name
241
     * @param value
242
     *            the value
243
     *
244
     * @return the property setter
245
     */
246
    static Method getPropertySetter(Class aClass, String propertyName, Object value) {
247
        Hashtable methodMap = (Hashtable) _classSetterMaps.get(aClass);
1✔
248
        if (methodMap == null) {
1✔
249
            _classSetterMaps.put(aClass, methodMap = new Hashtable<>());
1✔
250
        }
251

252
        Method result = (Method) methodMap.get(propertyName);
1✔
253
        if (result != null) {
1✔
254
            return result;
1✔
255
        }
256

257
        String setterName = "set" + Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1);
1✔
258
        Method[] methods = aClass.getMethods();
1✔
259
        for (Method method : methods) {
1!
260
            if (method.getName().equalsIgnoreCase(setterName) && method.getParameterTypes().length == 1
1!
261
                    && isConvertableTo(value.getClass(), method.getParameterTypes()[0])) {
1!
262
                methodMap.put(propertyName, method);
1✔
263
                return method;
1✔
264
            }
265
        }
266
        methodMap.put(propertyName, NO_SUCH_PROPERTY);
×
267
        return NO_SUCH_PROPERTY;
×
268
    }
269

270
    /**
271
     * check whether the valueType is convertable to the parameterType.
272
     *
273
     * @param valueType
274
     *            the value type
275
     * @param parameterType
276
     *            the parameter type
277
     *
278
     * @return true, if is convertable to
279
     */
280
    public static boolean isConvertableTo(Class valueType, Class parameterType) {
281
        if (valueType.equals(parameterType) || parameterType.equals(String.class)
1✔
282
                || valueType.equals(String.class) && isNumericParameter(parameterType)) {
1✔
283
            return true;
1✔
284
        }
285
        if (Number.class.isAssignableFrom(valueType) && isNumericParameter(parameterType)
1!
286
                || valueType.equals(Boolean.class) && parameterType.equals(boolean.class)) {
1!
287
            return true;
1✔
288
        }
289
        return valueType.equals(String.class) && parameterType.equals(Boolean.class);
1!
290
    }
291

292
    /**
293
     * Checks if is numeric parameter.
294
     *
295
     * @param parameterType
296
     *            the parameter type
297
     *
298
     * @return true, if is numeric parameter
299
     */
300
    private static boolean isNumericParameter(Class parameterType) {
301
        if (parameterType.isPrimitive() && !parameterType.equals(boolean.class)) {
1!
302
            return true;
1✔
303
        }
304
        return Number.class.isAssignableFrom(parameterType);
1✔
305
    }
306
}
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

© 2026 Coveralls, Inc