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

mybatis / ibatis-2 / 736

29 Dec 2025 12:23AM UTC coverage: 65.571% (-0.03%) from 65.597%
736

push

github

web-flow
Merge pull request #339 from hazendaz/master

Key set cleanup to use size directly increasing speed for same result

1598 of 2797 branches covered (57.13%)

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

149 existing lines in 7 files now uncovered.

5047 of 7697 relevant lines covered (65.57%)

0.66 hits per line

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

77.38
/src/main/java/com/ibatis/common/beans/ComplexBeanProbe.java
1
/*
2
 * Copyright 2004-2025 the original author or authors.
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
 *    https://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.ibatis.common.beans;
17

18
import com.ibatis.sqlmap.engine.mapping.result.ResultObjectFactoryUtil;
19

20
import java.util.Map;
21
import java.util.StringTokenizer;
22

23
/**
24
 * StaticBeanProbe provides methods that allow simple, reflective access to JavaBeans style properties. Methods are
25
 * provided for all simple types as well as object types.
26
 * <p>
27
 * Examples:
28
 * <p>
29
 * StaticBeanProbe.setObject(object, propertyName, value);
30
 * <p>
31
 * Object value = StaticBeanProbe.getObject(object, propertyName);
32
 */
33
public class ComplexBeanProbe extends BaseProbe {
34

35
  /** The Constant NO_ARGUMENTS. */
36
  private static final Object[] NO_ARGUMENTS = {};
1✔
37

38
  /**
39
   * Instantiates a new complex bean probe.
40
   */
41
  protected ComplexBeanProbe() {
1✔
42
  }
1✔
43

44
  /**
45
   * Returns an array of the readable properties exposed by a bean
46
   *
47
   * @param object
48
   *          The bean
49
   *
50
   * @return The properties
51
   */
52
  @Override
53
  public String[] getReadablePropertyNames(Object object) {
54
    return ClassInfo.getInstance(object.getClass()).getReadablePropertyNames();
×
55
  }
56

57
  /**
58
   * Returns an array of the writeable properties exposed by a bean
59
   *
60
   * @param object
61
   *          The bean
62
   *
63
   * @return The properties
64
   */
65
  @Override
66
  public String[] getWriteablePropertyNames(Object object) {
67
    return ClassInfo.getInstance(object.getClass()).getWriteablePropertyNames();
×
68
  }
69

70
  /**
71
   * Returns the class that the setter expects to receive as a parameter when setting a property value.
72
   *
73
   * @param object
74
   *          The bean to check
75
   * @param name
76
   *          The name of the property
77
   *
78
   * @return The type of the property
79
   */
80
  @Override
81
  public Class getPropertyTypeForSetter(Object object, String name) {
82
    Class type = object.getClass();
1✔
83

84
    if (object instanceof Class) {
1✔
85
      type = getClassPropertyTypeForSetter((Class) object, name);
1✔
86
    } else if (object instanceof Map) {
1✔
87
      Map map = (Map) object;
1✔
88
      Object value = map.get(name);
1✔
89
      if (value == null) {
1!
90
        type = Object.class;
1✔
91
      } else {
92
        type = value.getClass();
×
93
      }
94
    } else if (name.indexOf('.') > -1) {
1✔
95
      StringTokenizer parser = new StringTokenizer(name, ".");
1✔
96
      while (parser.hasMoreTokens()) {
1✔
97
        name = parser.nextToken();
1✔
98
        type = ClassInfo.getInstance(type).getSetterType(name);
1✔
99
      }
100
    } else {
1✔
101
      type = ClassInfo.getInstance(type).getSetterType(name);
1✔
102
    }
103

104
    return type;
1✔
105
  }
106

107
  /**
108
   * Returns the class that the getter will return when reading a property value.
109
   *
110
   * @param object
111
   *          The bean to check
112
   * @param name
113
   *          The name of the property
114
   *
115
   * @return The type of the property
116
   */
117
  @Override
118
  public Class getPropertyTypeForGetter(Object object, String name) {
119
    Class type = object.getClass();
1✔
120

121
    if (object instanceof Class) {
1!
UNCOV
122
      type = getClassPropertyTypeForGetter((Class) object, name);
×
123
    } else if (object instanceof Map) {
1!
124
      Map map = (Map) object;
×
UNCOV
125
      Object value = map.get(name);
×
126
      if (value == null) {
×
127
        type = Object.class;
×
128
      } else {
129
        type = value.getClass();
×
130
      }
131
    } else if (name.indexOf('.') > -1) {
1✔
132
      StringTokenizer parser = new StringTokenizer(name, ".");
1✔
133
      while (parser.hasMoreTokens()) {
1✔
134
        name = parser.nextToken();
1✔
135
        type = ClassInfo.getInstance(type).getGetterType(name);
1✔
136
      }
137
    } else {
1✔
138
      type = ClassInfo.getInstance(type).getGetterType(name);
1✔
139
    }
140

141
    return type;
1✔
142
  }
143

144
  /**
145
   * Returns the class that the getter will return when reading a property value.
146
   *
147
   * @param type
148
   *          The class to check
149
   * @param name
150
   *          The name of the property
151
   *
152
   * @return The type of the property
153
   */
154
  private Class getClassPropertyTypeForGetter(Class type, String name) {
155

UNCOV
156
    if (name.indexOf('.') > -1) {
×
UNCOV
157
      StringTokenizer parser = new StringTokenizer(name, ".");
×
UNCOV
158
      while (parser.hasMoreTokens()) {
×
UNCOV
159
        name = parser.nextToken();
×
160
        type = ClassInfo.getInstance(type).getGetterType(name);
×
161
      }
162
    } else {
×
163
      type = ClassInfo.getInstance(type).getGetterType(name);
×
164
    }
165

166
    return type;
×
167
  }
168

169
  /**
170
   * Returns the class that the setter expects to receive as a parameter when setting a property value.
171
   *
172
   * @param type
173
   *          The class to check
174
   * @param name
175
   *          The name of the property
176
   *
177
   * @return The type of the property
178
   */
179
  private Class getClassPropertyTypeForSetter(Class type, String name) {
180

181
    if (name.indexOf('.') > -1) {
1✔
182
      StringTokenizer parser = new StringTokenizer(name, ".");
1✔
183
      while (parser.hasMoreTokens()) {
1✔
184
        name = parser.nextToken();
1✔
185
        type = ClassInfo.getInstance(type).getSetterType(name);
1✔
186
      }
187
    } else {
1✔
188
      type = ClassInfo.getInstance(type).getSetterType(name);
1✔
189
    }
190

191
    return type;
1✔
192
  }
193

194
  /**
195
   * Gets an Object property from a bean
196
   *
197
   * @param object
198
   *          The bean
199
   * @param name
200
   *          The property name
201
   *
202
   * @return The property value (as an Object)
203
   */
204
  @Override
205
  public Object getObject(Object object, String name) {
206
    if (name.indexOf('.') <= -1) {
1✔
207
      return getProperty(object, name);
1✔
208
    }
209
    StringTokenizer parser = new StringTokenizer(name, ".");
1✔
210
    Object value = object;
1✔
211
    while (parser.hasMoreTokens()) {
1✔
212
      value = getProperty(value, parser.nextToken());
1✔
213

214
      if (value == null) {
1✔
215
        break;
1✔
216
      }
217

218
    }
219
    return value;
1✔
220
  }
221

222
  /**
223
   * Sets the value of a bean property to an Object
224
   *
225
   * @param object
226
   *          The bean to change
227
   * @param name
228
   *          The name of the property to set
229
   * @param value
230
   *          The new value to set
231
   */
232
  @Override
233
  public void setObject(Object object, String name, Object value) {
234
    if (name.indexOf('.') > -1) {
1✔
235
      StringTokenizer parser = new StringTokenizer(name, ".");
1✔
236
      String property = parser.nextToken();
1✔
237
      Object child = object;
1✔
238
      while (parser.hasMoreTokens()) {
1✔
239
        Class type = getPropertyTypeForSetter(child, property);
1✔
240
        Object parent = child;
1✔
241
        child = getProperty(parent, property);
1✔
242
        if (child == null) {
1✔
243
          if (value == null) {
1✔
244
            return; // don't instantiate child path if value is null
1✔
245
          }
246
          try {
247
            child = ResultObjectFactoryUtil.createObjectThroughFactory(type);
1✔
248
            setObject(parent, property, child);
1✔
UNCOV
249
          } catch (Exception e) {
×
UNCOV
250
            throw new ProbeException("Cannot set value of property '" + name + "' because '" + property
×
UNCOV
251
                + "' is null and cannot be instantiated on instance of " + type.getName() + ". Cause:" + e.toString(),
×
252
                e);
253
          }
1✔
254
        }
255
        property = parser.nextToken();
1✔
256
      }
1✔
257
      setProperty(child, property, value);
1✔
258
    } else {
1✔
259
      setProperty(object, name, value);
1✔
260
    }
261
  }
1✔
262

263
  /**
264
   * Checks to see if a bean has a writable property be a given name
265
   *
266
   * @param object
267
   *          The bean to check
268
   * @param propertyName
269
   *          The property to check for
270
   *
271
   * @return True if the property exists and is writable
272
   */
273
  @Override
274
  public boolean hasWritableProperty(Object object, String propertyName) {
275
    boolean hasProperty = false;
1✔
276
    if (object instanceof Map) {
1!
UNCOV
277
      hasProperty = true;// ((Map) object).containsKey(propertyName);
×
278
    } else if (propertyName.indexOf('.') > -1) {
1✔
279
      StringTokenizer parser = new StringTokenizer(propertyName, ".");
1✔
280
      Class type = object.getClass();
1✔
281
      while (parser.hasMoreTokens()) {
1✔
282
        propertyName = parser.nextToken();
1✔
283
        type = ClassInfo.getInstance(type).getGetterType(propertyName);
1✔
284
        hasProperty = ClassInfo.getInstance(type).hasWritableProperty(propertyName);
1✔
285
      }
286
    } else {
1✔
287
      hasProperty = ClassInfo.getInstance(object.getClass()).hasWritableProperty(propertyName);
1✔
288
    }
289
    return hasProperty;
1✔
290
  }
291

292
  /**
293
   * Checks to see if a bean has a readable property be a given name
294
   *
295
   * @param object
296
   *          The bean to check
297
   * @param propertyName
298
   *          The property to check for
299
   *
300
   * @return True if the property exists and is readable
301
   */
302
  @Override
303
  public boolean hasReadableProperty(Object object, String propertyName) {
304
    boolean hasProperty = false;
1✔
305
    if (object instanceof Map) {
1!
UNCOV
306
      hasProperty = true;// ((Map) object).containsKey(propertyName);
×
307
    } else if (propertyName.indexOf('.') > -1) {
1✔
308
      StringTokenizer parser = new StringTokenizer(propertyName, ".");
1✔
309
      Class type = object.getClass();
1✔
310
      while (parser.hasMoreTokens()) {
1✔
311
        propertyName = parser.nextToken();
1✔
312
        type = ClassInfo.getInstance(type).getGetterType(propertyName);
1✔
313
        hasProperty = ClassInfo.getInstance(type).hasReadableProperty(propertyName);
1✔
314
      }
315
    } else {
1✔
316
      hasProperty = ClassInfo.getInstance(object.getClass()).hasReadableProperty(propertyName);
1✔
317
    }
318
    return hasProperty;
1✔
319
  }
320

321
  @Override
322
  protected Object getProperty(Object object, String name) {
323
    try {
324
      Object value = null;
1✔
325
      if (name.indexOf('[') > -1) {
1✔
326
        value = getIndexedProperty(object, name);
1✔
327
      } else if (object instanceof Map) {
1✔
328
        int index = name.indexOf('.');
1✔
329
        if (index > -1) {
1✔
330
          String mapId = name.substring(0, index);
1✔
331
          value = getProperty(((Map) object).get(mapId), name.substring(index + 1));
1✔
332
        } else {
1✔
333
          value = ((Map) object).get(name);
1✔
334
        }
335

336
      } else {
1✔
337
        int index = name.indexOf('.');
1✔
338
        if (index > -1) {
1✔
339
          String newName = name.substring(0, index);
1✔
340
          value = getProperty(getObject(object, newName), name.substring(index + 1));
1✔
341
        } else {
1✔
342
          ClassInfo classCache = ClassInfo.getInstance(object.getClass());
1✔
343
          Invoker method = classCache.getGetInvoker(name);
1✔
344
          if (method == null) {
1!
UNCOV
345
            throw new NoSuchMethodException(
×
UNCOV
346
                "No GET method for property " + name + " on instance of " + object.getClass().getName());
×
347
          }
348
          try {
349
            value = method.invoke(object, NO_ARGUMENTS);
1✔
UNCOV
350
          } catch (Throwable t) {
×
UNCOV
351
            throw ClassInfo.unwrapThrowable(t);
×
352
          }
1✔
353
        }
354

355
      }
356
      return value;
1✔
357
    } catch (ProbeException e) {
×
UNCOV
358
      throw e;
×
UNCOV
359
    } catch (Throwable t) {
×
UNCOV
360
      if (object == null) {
×
361
        throw new ProbeException("Could not get property '" + name + "' from null reference.  Cause: " + t.toString(),
×
362
            t);
363
      }
UNCOV
364
      throw new ProbeException(
×
UNCOV
365
          "Could not get property '" + name + "' from " + object.getClass().getName() + ".  Cause: " + t.toString(), t);
×
366
    }
367
  }
368

369
  @Override
370
  protected void setProperty(Object object, String name, Object value) {
371
    ClassInfo classCache = ClassInfo.getInstance(object.getClass());
1✔
372
    try {
373
      if (name.indexOf('[') > -1) {
1!
UNCOV
374
        setIndexedProperty(object, name, value);
×
375
      } else if (object instanceof Map) {
1✔
376
        ((Map) object).put(name, value);
1✔
377
      } else {
378
        Invoker method = classCache.getSetInvoker(name);
1✔
379
        if (method == null) {
1!
UNCOV
380
          throw new NoSuchMethodException(
×
UNCOV
381
              "No SET method for property " + name + " on instance of " + object.getClass().getName());
×
382
        }
383
        Object[] params = new Object[1];
1✔
384
        params[0] = value;
1✔
385
        try {
386
          method.invoke(object, params);
1✔
387
        } catch (Throwable t) {
1✔
388
          throw ClassInfo.unwrapThrowable(t);
1✔
389
        }
1✔
390
      }
UNCOV
391
    } catch (ProbeException e) {
×
UNCOV
392
      throw e;
×
393
    } catch (Throwable t) {
1✔
394
      throw new ProbeException("Could not set property '" + name + "' to value '" + value + "' for "
1✔
395
          + object.getClass().getName() + ".  Cause: " + t.toString(), t);
1✔
396
    }
1✔
397
  }
1✔
398

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