지금 회사에서 ibatis 버전 2.3.4.726 을 사용 하고 있습니다. 이용할때 뜨문뜨문 에러가 발생했습니다. 에러 메시지는 아래와 같이 나왔습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13
CLASS_NAME : MappedStatement.java / LINE : 211 / MESSAGE : com.ibatis.common.jdbc.exception.NestedSQLException: --- The error occurred in com/mobon/dao/sql/mobon.xml. --- The error occurred while applying a result map. --- Check the mobon.selAdInfo-AutoResultMap. --- The error happened while setting a property on the result object. --- Cause: net.sf.cglib.beans.BulkBeanException CLASS_NAME : MappedStatement.java / LINE : 144 / MESSAGE : com.ibatis.common.jdbc.exception.NestedSQLException: --- The error occurred in com/mobon/dao/sql/mobon.xml. --- The error occurred while applying a result map. --- Check the mobon.selAdInfo-AutoResultMap. --- The error happened while setting a property on the result object. --- Cause: net.sf.cglib.beans.BulkBeanException
에러 메시지를 보고 궁금증이 들어서 ibatis code를 보았습니다. 에러가 났던 클래스는 MappedStatement.java(com.ibatis.sqlmap.engine.mapping.statement 패키지에 있습니다.) 에러가 난 메소드를 보면 아래와 같은 코드 입니다.
errorContext.setMoreInfo("Check the parameter map."); Object[] parameters = parameterMap.getParameterObjectValues(statementScope, parameterObject);
errorContext.setMoreInfo("Check the SQL statement."); String sqlString = sql.getSql(statementScope, parameterObject);
errorContext.setActivity("executing mapped statement"); errorContext.setMoreInfo("Check the SQL statement or the result map."); RowHandlerCallback callback = new RowHandlerCallback(resultMap, resultObject, rowHandler); sqlExecuteQuery(statementScope, conn, sqlString, parameters, skipResults, maxResults, callback);
errorContext.setMoreInfo("Check the output parameters."); if (parameterObject != null) { postProcessParameterObject(statementScope, parameterObject, parameters); }
public Object[] getResults(StatementScope statementScope, ResultSet rs) throws SQLException { ErrorContext errorContext = statementScope.getErrorContext(); errorContext.setActivity("applying a result map"); errorContext.setObjectId(this.getId()); errorContext.setResource(this.getResource()); errorContext.setMoreInfo("Check the result map.");
boolean foundData = false; Object[] columnValues = new Object[getResultMappings().length]; for (int i = 0; i < getResultMappings().length; i++) { ResultMapping mapping = (ResultMapping) getResultMappings()[i]; errorContext.setMoreInfo(mapping.getErrorString()); if (mapping.getStatementName() != null) { if (resultClass == null) { thrownew SqlMapException("The result class was null when trying to get results for ResultMap named " + getId() + "."); } elseif (Map.class.isAssignableFrom(resultClass)) { Class javaType = mapping.getJavaType(); if (javaType == null) { javaType = Object.class; } columnValues[i] = getNestedSelectMappingValue(statementScope, rs, mapping, javaType); } elseif (DomTypeMarker.class.isAssignableFrom(resultClass)) { Class javaType = mapping.getJavaType(); if (javaType == null) { javaType = DomTypeMarker.class; } columnValues[i] = getNestedSelectMappingValue(statementScope, rs, mapping, javaType); } else { Probe p = ProbeFactory.getProbe(resultClass); Class type = p.getPropertyTypeForSetter(resultClass, mapping.getPropertyName()); columnValues[i] = getNestedSelectMappingValue(statementScope, rs, mapping, type); } foundData = foundData || columnValues[i] != null; } elseif (mapping.getNestedResultMapName() == null) { columnValues[i] = getPrimitiveResultMappingValue(rs, mapping); if (columnValues[i] == null) { columnValues[i] = doNullMapping(columnValues[i], mapping); } else { foundData = true; } } }
다시 SqlExecutor에 handleResults 메소드를 보면 getResults 후에 callback.handleResultObject 호출 하는데 RowHandlerCallback.java(com.ibatis.sqlmap.engine.mapping.statement 패키지) class를 보면
if (object != ResultMap.NO_VALUE) { // XML Only special processing. (converts elements to string for easy insertion). int stackDepth = statementScope.getSession().getRequestStackDepth(); if (stackDepth == 1) { Class targetType = statementScope.getResultMap().getResultClass(); if (XmlTypeMarker.class.isAssignableFrom(targetType) && object instanceof Document) { object = documentToString((Document) object); } }
rowHandler.handleRow(object); } }
setResultObjectValues 메소드를 호출하는데 다시 찾아 보면 AutoResultMap.java(com.ibatis.sqlmap.engine.mapping.result 패키지) class의 setResultObjectValues 호출
1 2 3 4 5 6 7 8 9 10 11 12
public Object setResultObjectValues(StatementScope statementScope, Object resultObject, Object[] values){ // synchronization is only needed when remapping is enabled if (allowRemapping) { synchronized (this) { returnsuper.setResultObjectValues(statementScope, resultObject, values); } } returnsuper.setResultObjectValues(statementScope, resultObject, values); }
public Object setResultObjectValues(StatementScope statementScope, Object resultObject, Object[] values){ final String previousNestedKey = statementScope.getCurrentNestedKey(); String ukey = (String)getUniqueKey(statementScope.getCurrentNestedKey(), values); Map uniqueKeys = statementScope.getUniqueKeys(this); statementScope.setCurrentNestedKey(ukey); if (uniqueKeys != null && uniqueKeys.containsKey(ukey)) { // Unique key is already known, so get the existing result object and process additional results. resultObject = uniqueKeys.get(ukey); applyNestedResultMap(statementScope, resultObject, values); resultObject = NO_VALUE; } elseif (ukey == null || uniqueKeys == null || !uniqueKeys.containsKey(ukey)) { // Unique key is NOT known, so create a new result object and then process additional results. resultObject = dataExchange.setData(statementScope, this, resultObject, values); // Lazy init key set, only if we're grouped by something (i.e. ukey != null) if (ukey != null) { if (uniqueKeys == null) { uniqueKeys = new HashMap(); statementScope.setUniqueKeys(this, uniqueKeys); } uniqueKeys.put(ukey, resultObject); } applyNestedResultMap(statementScope, resultObject, values); } else { // Otherwise, we don't care about these results. resultObject = NO_VALUE; }
여기까지 오면 거의 다옴 그럼 여기서 보면 dataExchange.setData 를 호출함 DataExchange 를 상속받은 것이 여러가지가 있는데 우리가 볼것은 JavaBeanDataExchange.java(com.ibatis.sqlmap.engine.exchange 패키지) class에 setData 메소드 ```java public Object setData(StatementScope statementScope, ResultMap resultMap, Object resultObject, Object[] values) { if (resultPlan != null) { Object object = resultObject;
if (object == null) { errorContext.setMoreInfo("The error occured while instantiating the result object"); try { object = ResultObjectFactoryUtil.createObjectThroughFactory(resultMap.getResultClass()); } catch (Exception e) { thrownew RuntimeException("JavaBeansDataExchange could not instantiate result class. Cause: " + e, e); } } errorContext.setMoreInfo("The error happened while setting a property on the result object."); resultPlan.setProperties(object, values); return object; } else { returnnull; } }
최종 오류는 resultPlan.setProperties 하는 시점에 나온것이다 그럼 찾아 들어가면 AccessPlan.java 도 여러가지 클래스가 구현하고 있는데 EnhancedPropertyAccessPlan.java(com.ibatis.sqlmap.engine.accessplan 패키지) 클래스를 확인 하면