View Javadoc
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.sqlmap.engine.exchange;
17  
18  import com.ibatis.sqlmap.engine.accessplan.AccessPlan;
19  import com.ibatis.sqlmap.engine.accessplan.AccessPlanFactory;
20  import com.ibatis.sqlmap.engine.mapping.parameter.ParameterMap;
21  import com.ibatis.sqlmap.engine.mapping.parameter.ParameterMapping;
22  import com.ibatis.sqlmap.engine.mapping.result.ResultMap;
23  import com.ibatis.sqlmap.engine.mapping.result.ResultMapping;
24  import com.ibatis.sqlmap.engine.mapping.result.ResultObjectFactoryUtil;
25  import com.ibatis.sqlmap.engine.scope.ErrorContext;
26  import com.ibatis.sqlmap.engine.scope.StatementScope;
27  
28  import java.util.ArrayList;
29  import java.util.List;
30  import java.util.Map;
31  
32  /**
33   * DataExchange implementation for beans.
34   */
35  public class JavaBeanDataExchange extends BaseDataExchange implements DataExchange {
36  
37    /** The Constant NO_DATA. */
38    private static final Object[] NO_DATA = {};
39  
40    /** The result plan. */
41    private AccessPlan resultPlan;
42  
43    /** The parameter plan. */
44    private AccessPlan parameterPlan;
45  
46    /** The out param plan. */
47    private AccessPlan outParamPlan;
48  
49    /**
50     * Instantiates a new java bean data exchange.
51     *
52     * @param dataExchangeFactory
53     *          the data exchange factory
54     */
55    protected JavaBeanDataExchange(DataExchangeFactory dataExchangeFactory) {
56      super(dataExchangeFactory);
57    }
58  
59    /**
60     * Initializes the data exchange instance.
61     *
62     * @param properties
63     *          the properties
64     */
65    @Override
66    public void initialize(Map properties) {
67      Object map = properties.get("map");
68      if (map instanceof ParameterMap) {
69        ParameterMap parameterMap = (ParameterMap) map;
70        if (parameterMap != null) {
71          ParameterMapping[] parameterMappings = parameterMap.getParameterMappings();
72          String[] parameterPropNames = new String[parameterMappings.length];
73          for (int i = 0; i < parameterPropNames.length; i++) {
74            parameterPropNames[i] = parameterMappings[i].getPropertyName();
75          }
76          parameterPlan = AccessPlanFactory.getAccessPlan(parameterMap.getParameterClass(), parameterPropNames);
77  
78          // OUTPUT PARAMS
79          List outParamList = new ArrayList<>();
80          for (int i = 0; i < parameterPropNames.length; i++) {
81            if (parameterMappings[i].isOutputAllowed()) {
82              outParamList.add(parameterMappings[i].getPropertyName());
83            }
84          }
85          String[] outParams = (String[]) outParamList.toArray(new String[outParamList.size()]);
86          outParamPlan = AccessPlanFactory.getAccessPlan(parameterMap.getParameterClass(), outParams);
87        }
88  
89      } else if (map instanceof ResultMap) {
90        ResultMap resultMap = (ResultMap) map;
91        if (resultMap != null) {
92          ResultMapping[] resultMappings = resultMap.getResultMappings();
93          String[] resultPropNames = new String[resultMappings.length];
94          for (int i = 0; i < resultPropNames.length; i++) {
95            resultPropNames[i] = resultMappings[i].getPropertyName();
96          }
97          resultPlan = AccessPlanFactory.getAccessPlan(resultMap.getResultClass(), resultPropNames);
98        }
99      }
100   }
101 
102   @Override
103   public Object[] getData(StatementScope statementScope, ParameterMap parameterMap, Object parameterObject) {
104     if (parameterPlan != null) {
105       return parameterPlan.getProperties(parameterObject);
106     }
107     return NO_DATA;
108   }
109 
110   @Override
111   public Object setData(StatementScope statementScope, ResultMap resultMap, Object resultObject, Object[] values) {
112     if (resultPlan == null) {
113       return null;
114     }
115     Object object = resultObject;
116 
117     ErrorContext errorContext = statementScope.getErrorContext();
118 
119     if (object == null) {
120       errorContext.setMoreInfo("The error occured while instantiating the result object");
121       try {
122         object = ResultObjectFactoryUtil.createObjectThroughFactory(resultMap.getResultClass());
123       } catch (Exception e) {
124         throw new RuntimeException("JavaBeansDataExchange could not instantiate result class.  Cause: " + e, e);
125       }
126     }
127     errorContext.setMoreInfo("The error happened while setting a property on the result object.");
128     resultPlan.setProperties(object, values);
129     return object;
130   }
131 
132   // Bug ibatis-12
133   @Override
134   public Object setData(StatementScope statementScope, ParameterMap parameterMap, Object parameterObject,
135       Object[] values) {
136     if (outParamPlan == null) {
137       return null;
138     }
139     Object object = parameterObject;
140     if (object == null) {
141       try {
142         object = ResultObjectFactoryUtil.createObjectThroughFactory(parameterMap.getParameterClass());
143       } catch (Exception e) {
144         throw new RuntimeException("JavaBeansDataExchange could not instantiate parameter class. Cause: " + e, e);
145       }
146     }
147     values = getOutputParamValues(parameterMap.getParameterMappings(), values);
148     outParamPlan.setProperties(object, values);
149     return object;
150   }
151 
152   /**
153    * Gets the output param values.
154    *
155    * @param mappings
156    *          the mappings
157    * @param values
158    *          the values
159    *
160    * @return the output param values
161    */
162   private Object[] getOutputParamValues(ParameterMapping[] mappings, Object[] values) {
163     List outParamValues = new ArrayList<>();
164     for (int i = 0; i < mappings.length; i++) {
165       if (mappings[i].isOutputAllowed()) {
166         outParamValues.add(values[i]);
167       }
168     }
169     return outParamValues.toArray();
170   }
171 
172 }