MyBatis version

3.5.15

Database vendor and version

5.7.42

Test case or example project

xml sql is "select (case when subject_name='aaa[张三]' then subject_name else null end) as subject_name from als_core_p"

Steps to reproduce

To execute directly through MyBatis, it means executing database operations through MyBatis without any intermediate processes.

Expected result

have result

Actual result

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException:

Error querying database. Cause: java.lang.NumberFormatException: For input string: "张三"

Comment From: harawata

Hello @scf18857887860 ,

Please post the full stack trace (enclose it in ```).

Comment From: scf18857887860

Cause: java.lang.NumberFormatException: For input string: "张三" at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:96) ~[mybatis-spring-2.0.7.jar!/:2.0.7] at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:441) ~[mybatis-spring-2.0.7.jar!/:2.0.7] at com.sun.proxy.$Proxy146.selectList(Unknown Source) ~[na:na] at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:224) ~[mybatis-spring-2.0.7.jar!/:2.0.7] at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.executeForMany(MybatisMapperMethod.java:164) ~[mybatis-plus-core-3.5.5.jar!/:3.5.5] at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:77) ~[mybatis-plus-core-3.5.5.jar!/:3.5.5] at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:152) ~[mybatis-plus-core-3.5.5.jar!/:3.5.5] at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) ~[mybatis-plus-core-3.5.5.jar!/:3.5.5] at com.sun.proxy.$Proxy160.queryListByDynamicSql(Unknown Source) ~[na:na]

2024年1月11日 11:55,Iwao AVE! @.***> 写道:

Hello @scf18857887860 https://github.com/scf18857887860 ,

Please post the full stack trace (enclose it in ```).

— Reply to this email directly, view it on GitHub https://github.com/mybatis/mybatis-3/issues/3062#issuecomment-1886185073, or unsubscribe https://github.com/notifications/unsubscribe-auth/ADYYVI72XR4XNKSUC446KSTYN5PC7AVCNFSM6AAAAABBV2EOGOVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQOBWGE4DKMBXGM. You are receiving this because you were mentioned.

Comment From: harawata

Um..that seems like the top part of the stack. Is that all?

Comment From: scf18857887860

Cause: java.lang.NumberFormatException: For input string: "张三"
    at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:96) ~[mybatis-spring-2.0.7.jar!/:2.0.7]
    at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:441) ~[mybatis-spring-2.0.7.jar!/:2.0.7]
    at com.sun.proxy.$Proxy146.selectList(Unknown Source) ~[na:na]
    at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:224) ~[mybatis-spring-2.0.7.jar!/:2.0.7]
    at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.executeForMany(MybatisMapperMethod.java:164) ~[mybatis-plus-core-3.5.5.jar!/:3.5.5]
    at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:77) ~[mybatis-plus-core-3.5.5.jar!/:3.5.5]
    at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:152) ~[mybatis-plus-core-3.5.5.jar!/:3.5.5]
    at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) ~[mybatis-plus-core-3.5.5.jar!/:3.5.5]
    at com.sun.proxy.$Proxy160.queryListByDynamicSql(Unknown Source) ~[na:na]
    at com.mtc.report.infrastructure.template.repository.TemplateRepositoryImpl.queryListByDynamicSql(TemplateRepositoryImpl.java:74) ~[mh-report-infrastructure-1.0.0-SNAPSHOT.jar!/:1.0.0-SNAPSHOT]
    at com.mtc.report.domain.template.service.TemplateDomainService.queryTemplateData(TemplateDomainService.java:63) ~[mh-report-domain-1.0.0-SNAPSHOT.jar!/:1.0.0-SNAPSHOT]
    at com.mtc.report.adapter.web.TemplateController.sw$original$queryTemplateData$jcpelo3(TemplateController.java:37) ~[classes!/:1.0.0-SNAPSHOT]
    at com.mtc.report.adapter.web.TemplateController.sw$original$queryTemplateData$jcpelo3$accessor$sw$a99vf20(TemplateController.java) ~[classes!/:1.0.0-SNAPSHOT]
    at com.mtc.report.adapter.web.TemplateController$sw$auxiliary$vrm9v42.call(Unknown Source) ~[classes!/:1.0.0-SNAPSHOT]
    at org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstMethodsInter.intercept(InstMethodsInter.java:86) [skywalking-agent.jar:9.0.0]
    at com.mtc.report.adapter.web.TemplateController.queryTemplateData(TemplateController.java) ~[classes!/:1.0.0-SNAPSHOT]
    at sun.reflect.GeneratedMethodAccessor1012.invoke(Unknown Source) ~[na:na]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_342]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_342]
    at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:282) ~[spring-core-5.3.30.jar!/:5.3.30]
    at org.springframework.cloud.context.scope.GenericScope$LockedScopedProxyFactoryBean.invoke(GenericScope.java:485) ~[spring-cloud-context-3.1.7.jar!/:3.1.7]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.30.jar!/:5.3.30]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:762) ~[spring-aop-5.3.30.jar!/:5.3.30]
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:707) ~[spring-aop-5.3.30.jar!/:5.3.30]
    at com.mtc.report.adapter.web.TemplateController$$EnhancerBySpringCGLIB$$86ab94fd.queryTemplateData(<generated>) ~[classes!/:1.0.0-SNAPSHOT]
    at sun.reflect.GeneratedMethodAccessor1012.invoke(Unknown Source) ~[na:na]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_342]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_342]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-5.3.30.jar!/:5.3.30]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) ~[spring-web-5.3.30.jar!/:5.3.30]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) ~[spring-webmvc-5.3.30.jar!/:5.3.30]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-5.3.30.jar!/:5.3.30]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.30.jar!/:5.3.30]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.30.jar!/:5.3.30]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1072) ~[spring-webmvc-5.3.30.jar!/:5.3.30]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:965) ~[spring-webmvc-5.3.30.jar!/:5.3.30]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.30.jar!/:5.3.30]
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) ~[spring-webmvc-5.3.30.jar!/:5.3.30]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:517) [jakarta.servlet-api-4.0.4.jar!/:4.0.4]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.30.jar!/:5.3.30]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:584) [jakarta.servlet-api-4.0.4.jar!/:4.0.4]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:209) [tomcat-embed-core-9.0.80.jar!/:na]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) [tomcat-embed-core-9.0.80.jar!/:na]
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) [tomcat-embed-websocket-9.0.80.jar!/:na]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) [tomcat-embed-core-9.0.80.jar!/:na]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) [tomcat-embed-core-9.0.80.jar!/:na]
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) [spring-web-5.3.30.jar!/:5.3.30]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) [spring-web-5.3.30.jar!/:5.3.30]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) [tomcat-embed-core-9.0.80.jar!/:na]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) [tomcat-embed-core-9.0.80.jar!/:na]
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) [spring-web-5.3.30.jar!/:5.3.30]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) [spring-web-5.3.30.jar!/:5.3.30]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) [tomcat-embed-core-9.0.80.jar!/:na]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) [tomcat-embed-core-9.0.80.jar!/:na]
    at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:96) [spring-boot-actuator-2.7.16.jar!/:2.7.16]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) [spring-web-5.3.30.jar!/:5.3.30]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) [tomcat-embed-core-9.0.80.jar!/:na]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) [tomcat-embed-core-9.0.80.jar!/:na]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) [spring-web-5.3.30.jar!/:5.3.30]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) [spring-web-5.3.30.jar!/:5.3.30]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) [tomcat-embed-core-9.0.80.jar!/:na]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) [tomcat-embed-core-9.0.80.jar!/:na]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:168) [tomcat-embed-core-9.0.80.jar!/:na]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90) [tomcat-embed-core-9.0.80.jar!/:na]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:481) [tomcat-embed-core-9.0.80.jar!/:na]
    at org.apache.catalina.core.StandardHostValve.sw$original$invoke$s4bue91(StandardHostValve.java:130) [tomcat-embed-core-9.0.80.jar!/:na]
    at org.apache.catalina.core.StandardHostValve.sw$original$invoke$s4bue91$accessor$sw$p8ebm33(StandardHostValve.java) [tomcat-embed-core-9.0.80.jar!/:na]
    at org.apache.catalina.core.StandardHostValve$sw$auxiliary$evq4jr3.call(Unknown Source) [tomcat-embed-core-9.0.80.jar!/:na]
    at org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstMethodsInter.intercept(InstMethodsInter.java:86) [skywalking-agent.jar:9.0.0]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java) [tomcat-embed-core-9.0.80.jar!/:na]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) [tomcat-embed-core-9.0.80.jar!/:na]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [tomcat-embed-core-9.0.80.jar!/:na]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [tomcat-embed-core-9.0.80.jar!/:na]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:390) [tomcat-embed-core-9.0.80.jar!/:na]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) [tomcat-embed-core-9.0.80.jar!/:na]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:926) [tomcat-embed-core-9.0.80.jar!/:na]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1790) [tomcat-embed-core-9.0.80.jar!/:na]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) [tomcat-embed-core-9.0.80.jar!/:na]
    at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) [tomcat-embed-core-9.0.80.jar!/:na]
    at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) [tomcat-embed-core-9.0.80.jar!/:na]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.80.jar!/:na]
    at java.lang.Thread.run(Thread.java:750) [na:1.8.0_342]

Comment From: harawata

I guess you are trying to set the results to a Map. In that case, you cannot use [] in the column label, basically. [] is used to access list/array item and causes a problem like that.

I don't know any good solution other than changing the column alias in the SQL, unfortunately.

Comment From: scf18857887860

I guess you are trying to set the results to a Map. In that case, you cannot use [] in the column label, basically. [] is used to access list/array item and causes a problem like that.

I don't know any good solution other than changing the column alias in the SQL, unfortunately.

unfortunately,i can't use Map,because this string is custome data, I can't avoid,I hope there is a way to avoid MyBatis parsing these special characters.

Comment From: harawata

You are not using Map? Then I'm not sure what's wrong.

Please create a demo project and share it on your GitHub repository. We need to reproduce the same exception to investigate.

Here are some project templates and examples : https://github.com/harawata/mybatis-issues

And please ....

  • simplify the project (i.e. use minimum set of tables/columns/classes).
  • do not include mybatis-plus because it's not our product.

Comment From: scf18857887860

You are not using Map? Then I'm not sure what's wrong.

Please create a demo project and share it on your GitHub repository. We need to reproduce the same exception to investigate.

Here are some project templates and examples : https://github.com/harawata/mybatis-issues

And please ....

  • simplify the project (i.e. use minimum set of tables/columns/classes).
  • do not include mybatis-plus because it's not our product.

I do it,but I have no Permission and can't push,please give me enough Permission

Comment From: harawata

Here is what you need to do.

  1. Create the demo project and verify the same error reproduces.
  2. Create a new repository of your own. Make it 'public' so that we can see the files. https://docs.github.com/zh/repositories/creating-and-managing-repositories/creating-a-new-repository
  3. Then upload the files in your demo project to that repository.
    https://docs.github.com/zh/repositories/working-with-files/managing-files/adding-a-file-to-a-repository
  4. Let us know the repository URL.

Comment From: scf18857887860

Here is what you need to do.

  1. Create the demo project and verify the same error reproduces.
  2. Create a new repository of your own. Make it 'public' so that we can see the files. https://docs.github.com/zh/repositories/creating-and-managing-repositories/creating-a-new-repository
  3. Then upload the files in your demo project to that repository. https://docs.github.com/zh/repositories/working-with-files/managing-files/adding-a-file-to-a-repository
  4. Let us know the repository URL.

Hello, I've been waiting for a long time ,this is my repository url :git@github.com:scf18857887860/gh-3060.git, i write a test case name is “selectError” ,But I don't know if it's because of the database, the error here is not the same as mine.

Comment From: scf18857887860

I encountered a problem when I used MyBatis. When I used a map to receive the result set and the entire result set was empty, an empty map was returned, and there were no specified column names. However, I hope to return my column names. Is there a good solution? But I cannot use resultMap because it is a dynamic result set.

Comment From: scf18857887860

Hello, I have found the cause of this bug. Below is the specific code and description. However, there is currently no good solution. I hope you can notify me promptly after the subsequent version modification. ` DefaultResultSetHand#applyAutomaticMappings(){ List autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix); boolean foundValues = false; if (!autoMapping.isEmpty()) { for (UnMappedColumnAutoMapping mapping : autoMapping) { final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column); if (value != null) { foundValues = true; } if (value != null || configuration.isCallSettersOnNulls() && !mapping.primitive) { // gcode issue #377, call setter on nulls (value is not 'found') metaObject.setValue(mapping.property, value); } } } return foundValues; }

MetaObject#setValue(){ PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { MetaObject metaValue = metaObjectForProperty(prop.getIndexedName()); if (metaValue == SystemMetaObject.NULL_META_OBJECT) { if (value == null) { // don't instantiate child path if value is null return; } metaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory); } metaValue.setValue(prop.getChildren(), value); } else { objectWrapper.set(prop, value); } }

public PropertyTokenizer(String fullname) { int delim = fullname.indexOf('.'); if (delim > -1) { name = fullname.substring(0, delim); children = fullname.substring(delim + 1); } else { name = fullname; children = null; } indexedName = name; delim = name.indexOf('['); if (delim > -1) { index = name.substring(delim + 1, name.length() - 1); name = name.substring(0, delim); } }

BaseWrapper#setCollectionValue(){ if (collection instanceof Map) { ((Map) collection).put(prop.getIndex(), value); } else { int i = Integer.parseInt(prop.getIndex()); if (collection instanceof List) { ((List) collection).set(i, value); } else if (collection instanceof Object[]) { ((Object[]) collection)[i] = value; } else if (collection instanceof char[]) { ((char[]) collection)[i] = (Character) value; } else if (collection instanceof boolean[]) { ((boolean[]) collection)[i] = (Boolean) value; } else if (collection instanceof byte[]) { ((byte[]) collection)[i] = (Byte) value; } else if (collection instanceof double[]) { ((double[]) collection)[i] = (Double) value; } else if (collection instanceof float[]) { ((float[]) collection)[i] = (Float) value; } else if (collection instanceof int[]) { ((int[]) collection)[i] = (Integer) value; } else if (collection instanceof long[]) { ((long[]) collection)[i] = (Long) value; } else if (collection instanceof short[]) { ((short[]) collection)[i] = (Short) value; } else { throw new ReflectionException( "The '" + prop.getName() + "' property of " + collection + " is not a List or Array."); } } } `

The above is the specific code. The bold part is the entry point, because in this (PropertyTokenizer) class, my alias name is split using the special character '[]', causing the index in PropertyTokenizer to become a string, resulting in an error when subsequently converting the index to an integer.

Comment From: harawata

Well, that is basically what I explained in this comment.

A possible workaround is to write a custom ObjectWrapper. I sent a pull request to your repository. The test selectError will pass if you merge the PR.

Comment From: scf18857887860

Well, that is basically what I explained in this comment.

A possible workaround is to write a custom ObjectWrapper. I sent a pull request to your repository. The test selectError will pass if you merge the PR.

I think it would be possible to add some kind of escape character to skip the indexof for the bracket, as production environments are complex and it is likely that other special characters will be encountered. For example,\

Comment From: harawata

It's really difficult to change the core code because it could break existing applications. I hope you understand.

Comment From: scf18857887860

It's really difficult to change the core code because it could break existing applications. I hope you understand. For example,

public PropertyTokenizer(String fullname){
      if(fullname.startsWith("\\")){
            name=fullname.replace("\\","");
            return;
        }
int delim = fullname.indexOf('.');
    if (delim > -1) {
      name = fullname.substring(0, delim);
      children = fullname.substring(delim + 1);
    } else {
      name = fullname;
      children = null;
    }
    indexedName = name;
    delim = name.indexOf('[');
    if (delim > -1) {
      index = name.substring(delim + 1, name.length() - 1);
      name = name.substring(0, delim);
    }

}

Comment From: harawata

Thank you for the idea, but escape syntax does not help users who cannot control the column label. And if you can control the column label, you should be able to use a label that does not contain [.

ObjectWrapper is provided to support a minor usage without affecting majority of the users, so it is exactly what you should use.

I'll take a deeper look to see if there is room for improvement. Changing the visibility of MapWrapper.map field may make it easier to write a custom wrapper, for example.

diff --git a/src/main/java/org/apache/ibatis/reflection/wrapper/MapWrapper.java b/src/main/java/org/apache/ibatis/reflection/wrapper/MapWrapper.java
index 374b03e65b..e41df78459 100644
--- a/src/main/java/org/apache/ibatis/reflection/wrapper/MapWrapper.java
+++ b/src/main/java/org/apache/ibatis/reflection/wrapper/MapWrapper.java
@@ -29,7 +29,7 @@ import org.apache.ibatis.reflection.property.PropertyTokenizer;
  */
 public class MapWrapper extends BaseWrapper {

-  private final Map<String, Object> map;
+  protected final Map<String, Object> map;

   public MapWrapper(MetaObject metaObject, Map<String, Object> map) {
     super(metaObject);

I'll close this as the behavior is by design.

Comment From: scf18857887860

Thank you for the idea, but escape syntax does not help users who cannot control the column label. And if you can control the column label, you should be able to use a label that does not contain [.

ObjectWrapper is provided to support a minor usage without affecting majority of the users, so it is exactly what you should use.

I'll take a deeper look to see if there is room for improvement. Changing the visibility of MapWrapper.map field may make it easier to write a custom wrapper, for example.

```diff diff --git a/src/main/java/org/apache/ibatis/reflection/wrapper/MapWrapper.java b/src/main/java/org/apache/ibatis/reflection/wrapper/MapWrapper.java index 374b03e65b..e41df78459 100644 --- a/src/main/java/org/apache/ibatis/reflection/wrapper/MapWrapper.java +++ b/src/main/java/org/apache/ibatis/reflection/wrapper/MapWrapper.java @@ -29,7 +29,7 @@ import org.apache.ibatis.reflection.property.PropertyTokenizer; */ public class MapWrapper extends BaseWrapper {

  • private final Map map;
  • protected final Map map;

public MapWrapper(MetaObject metaObject, Map map) { super(metaObject); ```

I'll close this as the behavior is by design.

Ok, will this be released in the next version?

Comment From: scf18857887860

Thank you for the idea, but escape syntax does not help users who cannot control the column label. And if you can control the column label, you should be able to use a label that does not contain [.

ObjectWrapper is provided to support a minor usage without affecting majority of the users, so it is exactly what you should use.

I'll take a deeper look to see if there is room for improvement. Changing the visibility of MapWrapper.map field may make it easier to write a custom wrapper, for example.

```diff diff --git a/src/main/java/org/apache/ibatis/reflection/wrapper/MapWrapper.java b/src/main/java/org/apache/ibatis/reflection/wrapper/MapWrapper.java index 374b03e65b..e41df78459 100644 --- a/src/main/java/org/apache/ibatis/reflection/wrapper/MapWrapper.java +++ b/src/main/java/org/apache/ibatis/reflection/wrapper/MapWrapper.java @@ -29,7 +29,7 @@ import org.apache.ibatis.reflection.property.PropertyTokenizer; */ public class MapWrapper extends BaseWrapper {

  • private final Map map;
  • protected final Map map;

public MapWrapper(MetaObject metaObject, Map map) { super(metaObject); ```

I'll close this as the behavior is by design.

I have reviewed the source code and found that this modification does not seem to prevent the problem from occurring.


MapWrapper#set(PropertyTokenizer prop, Object value) {
if (prop.getIndex() != null) {
      Object collection = resolveCollection(prop, map);
      setCollectionValue(prop, collection, value);
    } else {
      map.put(prop.getName(), value);
    }
}

Comment From: harawata

You still need to write a custom ObjectWrapper and ObjectWrapperFactory. With the change in my comment, you can extend the built-in MapWrapper and override a few methods.

Comment From: scf18857887860

You still need to write a custom ObjectWrapper and ObjectWrapperFactory. With the change in my comment, you can extend the built-in MapWrapper and override a few methods.

MapWrapper#set(PropertyTokenizer prop, Object value) {
   String regex = "^\\d+$";
   Pattern pattern = Pattern.compile(regex);
   Matcher matcher = pattern.matcher(prop.getIndex());
   if (prop.getIndex() != null) {
       if(!matcher.matches())
       {
           map.put(prop.getIndexName(), value);
           return;
      }
      Object collection = resolveCollection(prop, map);
      setCollectionValue(prop, collection, value);
    } else {
      map.put(prop.getName(), value);
    }
}


this is ok?

Comment From: harawata

No, it is not OK. We will not support escape syntax. And I already explained why.

Please use the custom map wrapper in the pull request I sent.

Comment From: harawata

@scf18857887860 ,

The fix #3076 will be included in the next release (3.5.16). Until then, you can test the fix with the SNAPSHOT (see the wiki entry for how to use snapshot build). Please let me know the details if you find any problem.

Thank you for your contribution!