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