View Javadoc
1   /*
2    * Copyright 2004-2026 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.mapping.result.loader;
17  
18  import com.ibatis.common.beans.ClassInfo;
19  import com.ibatis.sqlmap.engine.impl.SqlMapClientImpl;
20  
21  import java.lang.reflect.InvocationHandler;
22  import java.lang.reflect.InvocationTargetException;
23  import java.lang.reflect.Method;
24  import java.lang.reflect.Proxy;
25  import java.sql.SQLException;
26  import java.util.Collection;
27  import java.util.List;
28  import java.util.Set;
29  
30  /**
31   * Class to lazily load results into objects.
32   */
33  public class LazyResultLoader implements InvocationHandler {
34  
35    /** The Constant SET_INTERFACES. */
36    private static final Class[] SET_INTERFACES = { Set.class };
37  
38    /** The Constant LIST_INTERFACES. */
39    private static final Class[] LIST_INTERFACES = { List.class };
40  
41    /** The client. */
42    protected SqlMapClientImpl client;
43  
44    /** The statement name. */
45    protected String statementName;
46  
47    /** The parameter object. */
48    protected Object parameterObject;
49  
50    /** The target type. */
51    protected Class targetType;
52  
53    /** The loaded. */
54    protected boolean loaded;
55  
56    /** The result object. */
57    protected Object resultObject;
58  
59    /**
60     * Constructor for a lazy list loader.
61     *
62     * @param client
63     *          - the client that is creating the lazy list
64     * @param statementName
65     *          - the statement to be used to build the list
66     * @param parameterObject
67     *          - the parameter object to be used to build the list
68     * @param targetType
69     *          - the type we are putting data into
70     */
71    public LazyResultLoader(SqlMapClientImpl client, String statementName, Object parameterObject, Class targetType) {
72      this.client = client;
73      this.statementName = statementName;
74      this.parameterObject = parameterObject;
75      this.targetType = targetType;
76    }
77  
78    /**
79     * Loads the result.
80     *
81     * @return the results - a list or object
82     *
83     * @throws SQLException
84     *           if there is a problem
85     */
86    public Object loadResult() throws SQLException {
87      if (!Collection.class.isAssignableFrom(targetType)) {
88        return ResultLoader.getResult(client, statementName, parameterObject, targetType);
89      }
90      InvocationHandler handler = new LazyResultLoader(client, statementName, parameterObject, targetType);
91      ClassLoader cl = targetType.getClassLoader();
92      if (Set.class.isAssignableFrom(targetType)) {
93        return Proxy.newProxyInstance(cl, SET_INTERFACES, handler);
94      }
95      return Proxy.newProxyInstance(cl, LIST_INTERFACES, handler);
96    }
97  
98    @Override
99    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
100     if ("finalize".hashCode() == method.getName().hashCode() && "finalize".equals(method.getName())) {
101       return null;
102     }
103     loadObject();
104     if (resultObject == null) {
105       return null;
106     }
107     try {
108       return method.invoke(resultObject, objects);
109     } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
110       throw ClassInfo.unwrapThrowable(e);
111     }
112   }
113 
114   /**
115    * Load object.
116    */
117   private synchronized void loadObject() {
118     if (!loaded) {
119       try {
120         loaded = true;
121         resultObject = ResultLoader.getResult(client, statementName, parameterObject, targetType);
122       } catch (SQLException e) {
123         throw new RuntimeException("Error lazy loading result. Cause: " + e, e);
124       }
125     }
126   }
127 
128 }