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.config;
17  
18  import com.ibatis.sqlmap.client.extensions.TypeHandlerCallback;
19  import com.ibatis.sqlmap.engine.impl.SqlMapClientImpl;
20  import com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate;
21  import com.ibatis.sqlmap.engine.mapping.result.Discriminator;
22  import com.ibatis.sqlmap.engine.mapping.result.ResultMap;
23  import com.ibatis.sqlmap.engine.mapping.result.ResultMapping;
24  import com.ibatis.sqlmap.engine.scope.ErrorContext;
25  import com.ibatis.sqlmap.engine.type.CustomTypeHandler;
26  import com.ibatis.sqlmap.engine.type.TypeHandler;
27  import com.ibatis.sqlmap.engine.type.TypeHandlerFactory;
28  
29  import java.util.ArrayList;
30  import java.util.Arrays;
31  import java.util.Iterator;
32  import java.util.List;
33  import java.util.StringTokenizer;
34  
35  /**
36   * The Class ResultMapConfig.
37   */
38  public class ResultMapConfig {
39  
40    /** The config. */
41    private SqlMapConfiguration config;
42  
43    /** The error context. */
44    private ErrorContext errorContext;
45  
46    /** The client. */
47    private SqlMapClientImpl client;
48  
49    /** The delegate. */
50    private SqlMapExecutorDelegate delegate;
51  
52    /** The type handler factory. */
53    private TypeHandlerFactory typeHandlerFactory;
54  
55    /** The result map. */
56    private ResultMap resultMap;
57  
58    /** The result mapping list. */
59    private List resultMappingList;
60  
61    /** The result mapping index. */
62    private int resultMappingIndex;
63  
64    /** The discriminator. */
65    private Discriminator discriminator;
66  
67    /**
68     * Instantiates a new result map config.
69     *
70     * @param config
71     *          the config
72     * @param id
73     *          the id
74     * @param resultClass
75     *          the result class
76     * @param groupBy
77     *          the group by
78     * @param extendsResultMap
79     *          the extends result map
80     * @param xmlName
81     *          the xml name
82     */
83    ResultMapConfig(SqlMapConfiguration config, String id, Class resultClass, String groupBy, String extendsResultMap,
84        String xmlName) {
85      this.config = config;
86      this.errorContext = config.getErrorContext();
87      this.client = config.getClient();
88      this.delegate = config.getDelegate();
89      this.typeHandlerFactory = config.getTypeHandlerFactory();
90      this.resultMap = new ResultMap(client.getDelegate());
91      this.resultMappingList = new ArrayList<>();
92      errorContext.setActivity("building a result map");
93      errorContext.setObjectId(id + " result map");
94      resultMap.setId(id);
95      resultMap.setXmlName(xmlName);
96      resultMap.setResource(errorContext.getResource());
97      if (groupBy != null && !groupBy.isEmpty()) {
98        StringTokenizer parser = new StringTokenizer(groupBy, ", ", false);
99        while (parser.hasMoreTokens()) {
100         resultMap.addGroupByProperty(parser.nextToken());
101       }
102     }
103     resultMap.setResultClass(resultClass);
104     errorContext.setMoreInfo("Check the extended result map.");
105     if (extendsResultMap != null) {
106       ResultMap extendedResultMap = client.getDelegate().getResultMap(extendsResultMap);
107       ResultMapping[] resultMappings = extendedResultMap.getResultMappings();
108       resultMappingList.addAll(Arrays.asList(resultMappings));
109       List nestedResultMappings = extendedResultMap.getNestedResultMappings();
110       if (nestedResultMappings != null) {
111         Iterator iter = nestedResultMappings.iterator();
112         while (iter.hasNext()) {
113           resultMap.addNestedResultMappings((ResultMapping) iter.next());
114         }
115       }
116       if ((groupBy == null || groupBy.isEmpty()) && extendedResultMap.hasGroupBy()) {
117         Iterator i = extendedResultMap.groupByProps();
118         while (i.hasNext()) {
119           resultMap.addGroupByProperty((String) i.next());
120         }
121       }
122     }
123     errorContext.setMoreInfo("Check the result mappings.");
124     resultMappingIndex = resultMappingList.size();
125     resultMap.setResultMappingList(resultMappingList);
126     client.getDelegate().addResultMap(resultMap);
127   }
128 
129   /**
130    * Sets the discriminator.
131    *
132    * @param columnName
133    *          the column name
134    * @param columnIndex
135    *          the column index
136    * @param javaClass
137    *          the java class
138    * @param jdbcType
139    *          the jdbc type
140    * @param nullValue
141    *          the null value
142    * @param typeHandlerImpl
143    *          the type handler impl
144    */
145   public void setDiscriminator(String columnName, Integer columnIndex, Class javaClass, String jdbcType,
146       String nullValue, Object typeHandlerImpl) {
147     TypeHandler handler;
148     if (typeHandlerImpl != null) {
149       if (typeHandlerImpl instanceof TypeHandlerCallback) {
150         handler = new CustomTypeHandler((TypeHandlerCallback) typeHandlerImpl);
151       } else if (typeHandlerImpl instanceof TypeHandler) {
152         handler = (TypeHandler) typeHandlerImpl;
153       } else {
154         throw new RuntimeException("The class '' is not a valid implementation of TypeHandler or TypeHandlerCallback");
155       }
156     } else {
157       handler = config.resolveTypeHandler(client.getDelegate().getTypeHandlerFactory(), resultMap.getResultClass(), "",
158           javaClass, jdbcType, true);
159     }
160     ResultMapping mapping = new ResultMapping();
161     mapping.setColumnName(columnName);
162     mapping.setJdbcTypeName(jdbcType);
163     mapping.setTypeHandler(handler);
164     mapping.setNullValue(nullValue);
165     mapping.setJavaType(javaClass);
166     if (columnIndex != null) {
167       mapping.setColumnIndex(columnIndex.intValue());
168     }
169     discriminator = new Discriminator(delegate, mapping);
170     resultMap.setDiscriminator(discriminator);
171   }
172 
173   /**
174    * Adds the discriminator sub map.
175    *
176    * @param value
177    *          the value
178    * @param resultMap
179    *          the result map
180    */
181   public void addDiscriminatorSubMap(Object value, String resultMap) {
182     if (discriminator == null) {
183       throw new RuntimeException("The discriminator is null, but somehow a subMap was reached.  This is a bug.");
184     }
185     discriminator.addSubMap(value.toString(), resultMap);
186   }
187 
188   /**
189    * Adds the result mapping.
190    *
191    * @param propertyName
192    *          the property name
193    * @param columnName
194    *          the column name
195    * @param columnIndex
196    *          the column index
197    * @param javaClass
198    *          the java class
199    * @param jdbcType
200    *          the jdbc type
201    * @param nullValue
202    *          the null value
203    * @param notNullColumn
204    *          the not null column
205    * @param statementName
206    *          the statement name
207    * @param resultMapName
208    *          the result map name
209    * @param impl
210    *          the impl
211    */
212   public void addResultMapping(String propertyName, String columnName, Integer columnIndex, Class javaClass,
213       String jdbcType, String nullValue, String notNullColumn, String statementName, String resultMapName,
214       Object impl) {
215     errorContext.setObjectId(propertyName + " mapping of the " + resultMap.getId() + " result map");
216     TypeHandler handler;
217     if (impl != null) {
218       if (impl instanceof TypeHandlerCallback) {
219         handler = new CustomTypeHandler((TypeHandlerCallback) impl);
220       } else if (impl instanceof TypeHandler) {
221         handler = (TypeHandler) impl;
222       } else {
223         throw new RuntimeException(
224             "The class '" + impl + "' is not a valid implementation of TypeHandler or TypeHandlerCallback");
225       }
226     } else {
227       handler = config.resolveTypeHandler(client.getDelegate().getTypeHandlerFactory(), resultMap.getResultClass(),
228           propertyName, javaClass, jdbcType, true);
229     }
230     ResultMapping mapping = new ResultMapping();
231     mapping.setPropertyName(propertyName);
232     mapping.setColumnName(columnName);
233     mapping.setJdbcTypeName(jdbcType);
234     mapping.setTypeHandler(handler);
235     mapping.setNullValue(nullValue);
236     mapping.setNotNullColumn(notNullColumn);
237     mapping.setStatementName(statementName);
238     mapping.setNestedResultMapName(resultMapName);
239     if (resultMapName != null && resultMapName.length() > 0) {
240       resultMap.addNestedResultMappings(mapping);
241     }
242     mapping.setJavaType(javaClass);
243     if (columnIndex != null) {
244       mapping.setColumnIndex(columnIndex.intValue());
245     } else {
246       resultMappingIndex++;
247       mapping.setColumnIndex(resultMappingIndex);
248     }
249     resultMappingList.add(mapping);
250     resultMap.setResultMappingList(resultMappingList);
251   }
252 
253 }