一、问题现象
java.lang.IllegalArgumentException: Illegal group reference@b@ at java.util.regex.Matcher.appendReplacement(Matcher.java:713)@b@ at java.util.regex.Matcher.replaceAll(Matcher.java:813)@b@ at java.lang.String.replaceAll(String.java:2189)@b@ at com.xxx.search.sword.pu.org.AreaLeaveProcessUnit.reverseRemoveWords(AreaLeaveProcessUnit.java:47)@b@ at com.xxx.search.sword.pu.org.AreaLeaveProcessUnit.splitArea(AreaLeaveProcessUnit.java:66)@b@ at com.xxx.search.sword.pu.org.AreaLeaveProcessUnit.split(AreaLeaveProcessUnit.java:115)@b@ at com.xxx.search.sword.ISegment.split(ISegment.java:64)@b@ at com.xxx.search.sword.SegmentManager.split(SegmentManager.java:49)@b@ at com.xxx.fsearch.utest.action.UTestAction.swordQuery(UTestAction.java:69)@b@ at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)@b@ at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)@b@ at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)@b@ at java.lang.reflect.Method.invoke(Method.java:597)@b@ at com.opensymphony.xwork2.DefaultActionInvocation.invokeAction(DefaultActionInvocation.java:450)@b@ at com.opensymphony.xwork2.DefaultActionInvocation.invokeActionOnly(DefaultActionInvocation.java:289)@b@ at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:252)@b@ at com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:167)@b@ at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)@b@ at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)@b@ at com.opensymphony.xwork2.validator.ValidationInterceptor.doIntercept(ValidationInterceptor.java:265)@b@ @b@ at @b@org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.doIntercept(AnnotationValidationInterceptor.java:68)@b@ at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)@b@ at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)@b@ at com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor.intercept(ConversionErrorInterceptor.java:138)@b@ at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)@b@ at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:239)@b@ at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)@b@ at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)@b@ at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:239)@b@ at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)@b@ at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)@b@ at com.opensymphony.xwork2.interceptor.StaticParametersInterceptor.intercept(StaticParametersInterceptor.java:191)@b@ at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)@b@ at org.apache.struts2.interceptor.FileUploadInterceptor.intercept(FileUploadInterceptor.java:252)@b@ at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)@b@ at com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor.intercept(ModelDrivenInterceptor.java:100)@b@ at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)@b@ at com.opensymphony.xwork2.interceptor.ChainingInterceptor.intercept(ChainingInterceptor.java:145)@b@ at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)@b@ at com.opensymphony.xwork2.interceptor.PrepareInterceptor.doIntercept(PrepareInterceptor.java:171)@b@ at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)@b@ at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)@b@ at org.apache.struts2.interceptor.ServletConfigInterceptor.intercept(ServletConfigInterceptor.java:164)@b@ at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)@b@ at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:239)@b@ at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)@b@ at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)@b@ at org.apache.struts2.interceptor.MultiselectInterceptor.intercept(MultiselectInterceptor.java:73)@b@ at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)@b@ at org.apache.struts2.interceptor.CheckboxInterceptor.intercept(CheckboxInterceptor.java:91)@b@ at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)@b@ at com.opensymphony.xwork2.interceptor.I18nInterceptor.intercept(I18nInterceptor.java:161)@b@ at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)@b@ at com.opensymphony.xwork2.interceptor.AliasInterceptor.intercept(AliasInterceptor.java:193)@b@ at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)@b@ at com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:189)@b@ at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)@b@ at org.apache.struts2.impl.StrutsActionProxy.execute(StrutsActionProxy.java:54)@b@ at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:563)@b@ at org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:77)@b@ at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:99)@b@ at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)@b@ at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)@b@ at com.asc.sf.sec.SecurityFilter.doFilter(SecurityFilter.java:48)@b@ at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)@b@ at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)@b@ at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:378)@b@ at org.springframework.security.intercept.web.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:99)@b@ at org.springframework.security.intercept.web.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)@b@ at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)@b@ at org.springframework.security.intercept.web.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:109)@b@ at org.springframework.security.intercept.web.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)@b@ at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)@b@ at org.springframework.security.ui.SessionFixationProtectionFilter.doFilterHttp(SessionFixationProtectionFilter.java:67)@b@ at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)@b@ at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)@b@ at org.springframework.security.ui.ExceptionTranslationFilter.doFilterHttp(ExceptionTranslationFilter.java:101)@b@ at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)@b@ at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)@b@ @b@ at @b@org.springframework.security.providers.anonymous.AnonymousProcessingFilter.doFilterHttp(AnonymousProcessingFilter.java:105)@b@ at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)@b@ at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)@b@ at org.springframework.security.ui.rememberme.RememberMeProcessingFilter.doFilterHttp(RememberMeProcessingFilter.java:116)@b@ at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)@b@ at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)@b@ @b@ at @b@org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter.doFilterHttp(SecurityContextHolderAwareRequestFilter.java:91)@b@ at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)@b@ at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)@b@ at org.springframework.security.ui.AbstractProcessingFilter.doFilterHttp(AbstractProcessingFilter.java:278)@b@ at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)@b@ at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)@b@ at org.springframework.security.ui.logout.LogoutFilter.doFilterHttp(LogoutFilter.java:89)@b@ at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)@b@ at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)@b@ @b@ at @b@org.springframework.security.context.HttpSessionContextIntegrationFilter.doFilterHttp(HttpSessionContextIntegrationFilter.java:235)@b@ at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)@b@ at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)@b@ at org.springframework.security.concurrent.ConcurrentSessionFilter.doFilterHttp(ConcurrentSessionFilter.java:99)@b@ at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)@b@ at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)@b@ at org.springframework.security.util.FilterChainProxy.doFilter(FilterChainProxy.java:175)@b@ at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:343)@b@ at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:260)@b@ at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)@b@ at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)@b@ at org.ajaxanywhere.AAFilter.doFilter(AAFilter.java:65)@b@ at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)@b@ at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)@b@ at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)@b@ at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)@b@ at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)@b@ at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)@b@ at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)@b@ at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)@b@ at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)@b@ at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)@b@ at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)@b@ at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)@b@ at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:857)@b@ at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)@b@ at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)@b@ at java.lang.Thread.run(Thread.java:662)
二、模拟重现
示例代码,如下
public static void main(String[] args) {@b@ String sk="$-$";@b@ String kk="123421".replaceAll("2", sk);@b@ }
运行结果,同样抛出java.lang.IllegalArgumentException: Illegal group reference异常
Exception in thread "main" java.lang.IllegalArgumentException: Illegal group reference@b@ at java.util.regex.Matcher.appendReplacement(Matcher.java:713)@b@ at java.util.regex.Matcher.replaceAll(Matcher.java:813)@b@ at java.lang.String.replaceAll(String.java:2189)@b@ at jh.modules.Java.main(Java.java:8)
三、解答原因
观察模拟重新代码运行的异常轨迹,可以判断是因为JDK提供java.util.regex.Matcher引起的,下面我们看下具体抛出异常的源码部分
/* */ public Matcher appendReplacement(StringBuffer paramStringBuffer, String paramString)@b@/* */ {@b@/* 691 */ if (this.first < 0) {@b@/* 692 */ throw new IllegalStateException("No match available");@b@/* */ }@b@/* */ @b@/* 695 */ int i = 0;@b@/* 696 */ String str = paramString;@b@/* 697 */ StringBuffer localStringBuffer = new StringBuffer();@b@/* */ @b@/* 699 */ while (i < paramString.length()) {@b@/* 700 */ char c = paramString.charAt(i);@b@/* 701 */ if (c == '') {@b@/* 702 */ ++i;@b@/* 703 */ c = paramString.charAt(i);@b@/* 704 */ localStringBuffer.append(c);@b@/* 705 */ ++i;@b@/* 706 */ } else if (c == '$')@b@/* */ {@b@/* 708 */ ++i;@b@/* */ @b@/* 711 */ int j = paramString.charAt(i) - '0';@b@/* 712 */ if ((j < 0) || (j > 9)) {@b@/* 713 */ throw new IllegalArgumentException("Illegal group reference");@b@/* */ }@b@/* 715 */ ++i;@b@/* */ @b@/* 718 */ int k = 0;@b@/* 719 */ while (k == 0) {@b@/* 720 */ if (i >= paramString.length()) {@b@/* */ break;@b@/* */ }@b@/* 723 */ int l = paramString.charAt(i) - '0';@b@/* 724 */ if (l < 0) break; if (l > 9) {@b@/* */ break;@b@/* */ }@b@/* 727 */ int i1 = j * 10 + l;@b@/* 728 */ if (groupCount() < i1) {@b@/* 729 */ k = 1;@b@/* */ } else {@b@/* 731 */ j = i1;@b@/* 732 */ ++i;@b@/* */ }@b@/* */ @b@/* */ }@b@/* */ @b@/* 737 */ if (group(j) != null)@b@/* 738 */ localStringBuffer.append(group(j));@b@/* */ } else {@b@/* 740 */ localStringBuffer.append(c);@b@/* 741 */ ++i;@b@/* */ }@b@/* */ @b@/* */ }@b@/* */ @b@/* 746 */ paramStringBuffer.append(getSubSequence(this.lastAppendPosition, this.first));@b@/* */ @b@/* 748 */ paramStringBuffer.append(localStringBuffer.toString());@b@/* */ @b@/* 750 */ this.lastAppendPosition = this.last;@b@/* 751 */ return this;@b@/* */ }
通过上面源码,我们可以清楚的看出第713行抛出了问题异常,在向上第706行查看执行该逻辑的前提条件 -被替换的字符中包含有'$',回到模拟重现代码中String sk="$-$";所以我们找到问题的答案,被替换的字符中不能包含特殊字符'$'