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

mybatis / ibatis-2 / 730

28 Dec 2025 10:16PM UTC coverage: 65.615% (+0.5%) from 65.146%
730

push

github

web-flow
Update README.md

1602 of 2802 branches covered (57.17%)

5053 of 7701 relevant lines covered (65.61%)

0.66 hits per line

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

77.06
/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 {
1✔
95
      if (name.indexOf('.') > -1) {
1✔
96
        StringTokenizer parser = new StringTokenizer(name, ".");
1✔
97
        while (parser.hasMoreTokens()) {
1✔
98
          name = parser.nextToken();
1✔
99
          type = ClassInfo.getInstance(type).getSetterType(name);
1✔
100
        }
101
      } else {
1✔
102
        type = ClassInfo.getInstance(type).getSetterType(name);
1✔
103
      }
104
    }
105

106
    return type;
1✔
107
  }
108

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

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

145
    return type;
1✔
146
  }
147

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

160
    if (name.indexOf('.') > -1) {
×
161
      StringTokenizer parser = new StringTokenizer(name, ".");
×
162
      while (parser.hasMoreTokens()) {
×
163
        name = parser.nextToken();
×
164
        type = ClassInfo.getInstance(type).getGetterType(name);
×
165
      }
166
    } else {
×
167
      type = ClassInfo.getInstance(type).getGetterType(name);
×
168
    }
169

170
    return type;
×
171
  }
172

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

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

195
    return type;
1✔
196
  }
197

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

216
        if (value == null) {
1✔
217
          break;
1✔
218
        }
219

220
      }
221
      return value;
1✔
222
    } else {
223
      return getProperty(object, name);
1✔
224
    }
225
  }
226

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

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

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

331
  @Override
332
  protected Object getProperty(Object object, String name) {
333
    try {
334
      Object value = null;
1✔
335
      if (name.indexOf('[') > -1) {
1✔
336
        value = getIndexedProperty(object, name);
1✔
337
      } else {
338
        if (object instanceof Map) {
1✔
339
          int index = name.indexOf('.');
1✔
340
          if (index > -1) {
1✔
341
            String mapId = name.substring(0, index);
1✔
342
            value = getProperty(((Map) object).get(mapId), name.substring(index + 1));
1✔
343
          } else {
1✔
344
            value = ((Map) object).get(name);
1✔
345
          }
346

347
        } else {
1✔
348
          int index = name.indexOf('.');
1✔
349
          if (index > -1) {
1✔
350
            String newName = name.substring(0, index);
1✔
351
            value = getProperty(getObject(object, newName), name.substring(index + 1));
1✔
352
          } else {
1✔
353
            ClassInfo classCache = ClassInfo.getInstance(object.getClass());
1✔
354
            Invoker method = classCache.getGetInvoker(name);
1✔
355
            if (method == null) {
1!
356
              throw new NoSuchMethodException(
×
357
                  "No GET method for property " + name + " on instance of " + object.getClass().getName());
×
358
            }
359
            try {
360
              value = method.invoke(object, NO_ARGUMENTS);
1✔
361
            } catch (Throwable t) {
×
362
              throw ClassInfo.unwrapThrowable(t);
×
363
            }
1✔
364
          }
365

366
        }
367
      }
368
      return value;
1✔
369
    } catch (ProbeException e) {
×
370
      throw e;
×
371
    } catch (Throwable t) {
×
372
      if (object == null) {
×
373
        throw new ProbeException("Could not get property '" + name + "' from null reference.  Cause: " + t.toString(),
×
374
            t);
375
      } else {
376
        throw new ProbeException(
×
377
            "Could not get property '" + name + "' from " + object.getClass().getName() + ".  Cause: " + t.toString(),
×
378
            t);
379
      }
380
    }
381
  }
382

383
  @Override
384
  protected void setProperty(Object object, String name, Object value) {
385
    ClassInfo classCache = ClassInfo.getInstance(object.getClass());
1✔
386
    try {
387
      if (name.indexOf('[') > -1) {
1!
388
        setIndexedProperty(object, name, value);
×
389
      } else {
390
        if (object instanceof Map) {
1✔
391
          ((Map) object).put(name, value);
1✔
392
        } else {
393
          Invoker method = classCache.getSetInvoker(name);
1✔
394
          if (method == null) {
1!
395
            throw new NoSuchMethodException(
×
396
                "No SET method for property " + name + " on instance of " + object.getClass().getName());
×
397
          }
398
          Object[] params = new Object[1];
1✔
399
          params[0] = value;
1✔
400
          try {
401
            method.invoke(object, params);
1✔
402
          } catch (Throwable t) {
1✔
403
            throw ClassInfo.unwrapThrowable(t);
1✔
404
          }
1✔
405
        }
406
      }
407
    } catch (ProbeException e) {
×
408
      throw e;
×
409
    } catch (Throwable t) {
1✔
410
      throw new ProbeException("Could not set property '" + name + "' to value '" + value + "' for "
1✔
411
          + object.getClass().getName() + ".  Cause: " + t.toString(), t);
1✔
412
    }
1✔
413
  }
1✔
414

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