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