View Javadoc
1   /*
2    *    Copyright 2009-2024 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 org.apache.ibatis.reflection.wrapper;
17  
18  import java.util.List;
19  
20  import org.apache.ibatis.reflection.ExceptionUtil;
21  import org.apache.ibatis.reflection.MetaClass;
22  import org.apache.ibatis.reflection.MetaObject;
23  import org.apache.ibatis.reflection.ReflectionException;
24  import org.apache.ibatis.reflection.SystemMetaObject;
25  import org.apache.ibatis.reflection.factory.ObjectFactory;
26  import org.apache.ibatis.reflection.invoker.Invoker;
27  import org.apache.ibatis.reflection.property.PropertyTokenizer;
28  
29  /**
30   * @author Clinton Begin
31   */
32  public class BeanWrapper extends BaseWrapper {
33  
34    private final Object object;
35    private final MetaClass metaClass;
36  
37    public BeanWrapper(MetaObject metaObject, Object object) {
38      super(metaObject);
39      this.object = object;
40      this.metaClass = MetaClass.forClass(object.getClass(), metaObject.getReflectorFactory());
41    }
42  
43    @Override
44    public Object get(PropertyTokenizer prop) {
45      if (prop.hasNext()) {
46        return getChildValue(prop);
47      } else if (prop.getIndex() != null) {
48        return getCollectionValue(prop, resolveCollection(prop, object));
49      } else {
50        return getBeanProperty(prop, object);
51      }
52    }
53  
54    @Override
55    public void set(PropertyTokenizer prop, Object value) {
56      if (prop.hasNext()) {
57        setChildValue(prop, value);
58      } else if (prop.getIndex() != null) {
59        setCollectionValue(prop, resolveCollection(prop, object), value);
60      } else {
61        setBeanProperty(prop, object, value);
62      }
63    }
64  
65    @Override
66    public String findProperty(String name, boolean useCamelCaseMapping) {
67      return metaClass.findProperty(name, useCamelCaseMapping);
68    }
69  
70    @Override
71    public String[] getGetterNames() {
72      return metaClass.getGetterNames();
73    }
74  
75    @Override
76    public String[] getSetterNames() {
77      return metaClass.getSetterNames();
78    }
79  
80    @Override
81    public Class<?> getSetterType(String name) {
82      PropertyTokenizer prop = new PropertyTokenizer(name);
83      if (!prop.hasNext()) {
84        return metaClass.getSetterType(name);
85      }
86      MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
87      if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
88        return metaClass.getSetterType(name);
89      }
90      return metaValue.getSetterType(prop.getChildren());
91    }
92  
93    @Override
94    public Class<?> getGetterType(String name) {
95      PropertyTokenizer prop = new PropertyTokenizer(name);
96      if (!prop.hasNext()) {
97        return metaClass.getGetterType(name);
98      }
99      MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
100     if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
101       return metaClass.getGetterType(name);
102     }
103     return metaValue.getGetterType(prop.getChildren());
104   }
105 
106   @Override
107   public boolean hasSetter(String name) {
108     PropertyTokenizer prop = new PropertyTokenizer(name);
109     if (!prop.hasNext()) {
110       return metaClass.hasSetter(name);
111     }
112     if (metaClass.hasSetter(prop.getIndexedName())) {
113       MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
114       if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
115         return metaClass.hasSetter(name);
116       }
117       return metaValue.hasSetter(prop.getChildren());
118     }
119     return false;
120   }
121 
122   @Override
123   public boolean hasGetter(String name) {
124     PropertyTokenizer prop = new PropertyTokenizer(name);
125     if (!prop.hasNext()) {
126       return metaClass.hasGetter(name);
127     }
128     if (metaClass.hasGetter(prop.getIndexedName())) {
129       MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
130       if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
131         return metaClass.hasGetter(name);
132       }
133       return metaValue.hasGetter(prop.getChildren());
134     }
135     return false;
136   }
137 
138   @Override
139   public MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory) {
140     MetaObject metaValue;
141     Class<?> type = getSetterType(prop.getName());
142     try {
143       Object newObject = objectFactory.create(type);
144       metaValue = MetaObject.forObject(newObject, metaObject.getObjectFactory(), metaObject.getObjectWrapperFactory(),
145           metaObject.getReflectorFactory());
146       set(prop, newObject);
147     } catch (Exception e) {
148       throw new ReflectionException("Cannot set value of property '" + name + "' because '" + name
149           + "' is null and cannot be instantiated on instance of " + type.getName() + ". Cause:" + e.toString(), e);
150     }
151     return metaValue;
152   }
153 
154   private Object getBeanProperty(PropertyTokenizer prop, Object object) {
155     try {
156       Invoker method = metaClass.getGetInvoker(prop.getName());
157       try {
158         return method.invoke(object, NO_ARGUMENTS);
159       } catch (Throwable t) {
160         throw ExceptionUtil.unwrapThrowable(t);
161       }
162     } catch (RuntimeException e) {
163       throw e;
164     } catch (Throwable t) {
165       throw new ReflectionException(
166           "Could not get property '" + prop.getName() + "' from " + object.getClass() + ".  Cause: " + t.toString(), t);
167     }
168   }
169 
170   private void setBeanProperty(PropertyTokenizer prop, Object object, Object value) {
171     try {
172       Invoker method = metaClass.getSetInvoker(prop.getName());
173       Object[] params = { value };
174       try {
175         method.invoke(object, params);
176       } catch (Throwable t) {
177         throw ExceptionUtil.unwrapThrowable(t);
178       }
179     } catch (Throwable t) {
180       throw new ReflectionException("Could not set property '" + prop.getName() + "' of '" + object.getClass()
181           + "' with value '" + value + "' Cause: " + t.toString(), t);
182     }
183   }
184 
185   @Override
186   public boolean isCollection() {
187     return false;
188   }
189 
190   @Override
191   public void add(Object element) {
192     throw new UnsupportedOperationException();
193   }
194 
195   @Override
196   public <E> void addAll(List<E> list) {
197     throw new UnsupportedOperationException();
198   }
199 
200 }