Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-20768

Comparison method violates its general contract exception

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: Major Major
    • xfpanel-plugin
    • None

      It get the stacktrace below sometimes. I have not found a clear pattern in when it happens.
      However I have seen similar errors in other code running on JDK 7.
      I am running 1.2.2

      To me it looks like the selectComparator.compare in XFPanelView is wrong. It contains.

      // if build is null, show it on bottom of its class
      if ( buildA == null || buildB == null )

      { return ( buildA == null ) ? 1 : 0; }

      // if building atm -> show build on top of its class
      if ( buildA.isBuilding() || buildB.isBuilding() )

      { return ( buildA.isBuilding() ) ? 0 : 1; }

      It does not follow the contract that says:
      "The implementor must ensure that sgn(compare(x, y)) == -sgn(compare(y, x)) for all x and y. "

      It should be changed to:

      // if build is null, show it on bottom of its class
      if ( buildA == null || buildB == null ){
      if (buildA == buildB)

      { return 0; }
      return ( buildA == null ) ? 1 : 0;
      }

      // if building atm -> show build on top of its class
      if ( buildA.isBuilding() || buildB.isBuilding() ){
      if (buildA.isBuilding() == buildB.isBuilding()) { return 0; }

      return ( buildA.isBuilding() ) ? 0 : 1;
      }

      Status Code: 500
      Exception: org.apache.commons.jelly.JellyTagException: file:/D:/JenkinsHome/plugins/xfpanel/WEB-INF/classes/maps/hudson/plugin/xfpanel/XFPanelView/maindisplay.jelly:23:53: <j:invoke> method sort threw exception: Comparison method violates its general contract!
      Stacktrace:
      javax.servlet.ServletException: org.apache.commons.jelly.JellyTagException: file:/D:/JenkinsHome/plugins/xfpanel/WEB-INF/classes/maps/hudson/plugin/xfpanel/XFPanelView/maindisplay.jelly:23:53: <j:invoke> method sort threw exception: Comparison method violates its general contract!
      at org.kohsuke.stapler.jelly.JellyFacet$1.dispatch(JellyFacet.java:103)
      at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:677)
      at org.kohsuke.stapler.Stapler.invoke(Stapler.java:770)
      at org.kohsuke.stapler.MetaClass$6.doDispatch(MetaClass.java:241)
      at org.kohsuke.stapler.NameBasedDispatcher.dispatch(NameBasedDispatcher.java:53)
      at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:677)
      at org.kohsuke.stapler.Stapler.invoke(Stapler.java:770)
      at org.kohsuke.stapler.Stapler.invoke(Stapler.java:583)
      at org.kohsuke.stapler.Stapler.service(Stapler.java:214)
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
      at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:95)
      at net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:206)
      at net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:179)
      at net.bull.javamelody.PluginMonitoringFilter.doFilter(PluginMonitoringFilter.java:86)
      at org.jvnet.hudson.plugins.monitoring.HudsonMonitoringFilter.doFilter(HudsonMonitoringFilter.java:84)
      at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:98)
      at hudson.plugins.greenballs.GreenBallFilter.doFilter(GreenBallFilter.java:58)
      at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:98)
      at hudson.plugins.audit_trail.AuditTrailFilter.doFilter(AuditTrailFilter.java:66)
      at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:98)
      at hudson.util.PluginServletFilter.doFilter(PluginServletFilter.java:87)
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
      at hudson.security.csrf.CrumbFilter.doFilter(CrumbFilter.java:48)
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
      at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:84)
      at hudson.security.UnwrapSecurityExceptionFilter.doFilter(UnwrapSecurityExceptionFilter.java:51)
      at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)
      at org.acegisecurity.ui.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:124)
      at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)
      at org.acegisecurity.providers.anonymous.AnonymousProcessingFilter.doFilter(AnonymousProcessingFilter.java:125)
      at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)
      at org.acegisecurity.ui.rememberme.RememberMeProcessingFilter.doFilter(RememberMeProcessingFilter.java:142)
      at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)
      at org.acegisecurity.ui.AbstractProcessingFilter.doFilter(AbstractProcessingFilter.java:271)
      at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)
      at org.acegisecurity.ui.basicauth.BasicProcessingFilter.doFilter(BasicProcessingFilter.java:174)
      at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)
      at jenkins.security.ApiTokenFilter.doFilter(ApiTokenFilter.java:64)
      at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)
      at org.acegisecurity.context.HttpSessionContextIntegrationFilter.doFilter(HttpSessionContextIntegrationFilter.java:249)
      at hudson.security.HttpSessionContextIntegrationFilter2.doFilter(HttpSessionContextIntegrationFilter2.java:67)
      at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)
      at hudson.security.ChainedServletFilter.doFilter(ChainedServletFilter.java:76)
      at hudson.security.HudsonFilter.doFilter(HudsonFilter.java:164)
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
      at org.kohsuke.stapler.compression.CompressionFilter.doFilter(CompressionFilter.java:50)
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
      at hudson.util.CharacterEncodingFilter.doFilter(CharacterEncodingFilter.java:81)
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
      at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
      at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
      at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
      at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
      at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
      at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:947)
      at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
      at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
      at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1009)
      at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
      at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
      at java.lang.Thread.run(Thread.java:722)
      Caused by: org.apache.commons.jelly.JellyTagException: file:/D:/JenkinsHome/plugins/xfpanel/WEB-INF/classes/maps/hudson/plugin/xfpanel/XFPanelView/maindisplay.jelly:23:53: <j:invoke> method sort threw exception: Comparison method violates its general contract!
      at org.apache.commons.jelly.tags.core.InvokeTag.doTag(InvokeTag.java:109)
      at org.apache.commons.jelly.impl.TagScript.run(TagScript.java:269)
      at org.apache.commons.jelly.impl.ScriptBlock.run(ScriptBlock.java:95)
      at org.kohsuke.stapler.jelly.ReallyStaticTagLibrary$1.run(ReallyStaticTagLibrary.java:99)
      at org.apache.commons.jelly.TagSupport.invokeBody(TagSupport.java:161)
      at org.apache.commons.jelly.tags.core.OtherwiseTag.doTag(OtherwiseTag.java:41)
      at org.apache.commons.jelly.impl.TagScript.run(TagScript.java:269)
      at org.apache.commons.jelly.impl.ScriptBlock.run(ScriptBlock.java:95)
      at org.apache.commons.jelly.TagSupport.invokeBody(TagSupport.java:161)
      at org.apache.commons.jelly.tags.core.ChooseTag.doTag(ChooseTag.java:38)
      at org.apache.commons.jelly.impl.TagScript.run(TagScript.java:269)
      at org.apache.commons.jelly.tags.core.CoreTagLibrary$2.run(CoreTagLibrary.java:105)
      at org.kohsuke.stapler.jelly.JellyViewScript.run(JellyViewScript.java:81)
      at org.kohsuke.stapler.jelly.IncludeTag.doTag(IncludeTag.java:146)
      at org.apache.commons.jelly.impl.TagScript.run(TagScript.java:269)
      at org.apache.commons.jelly.impl.ScriptBlock.run(ScriptBlock.java:95)
      at org.kohsuke.stapler.jelly.CallTagLibScript$1.run(CallTagLibScript.java:98)
      at org.apache.commons.jelly.tags.define.InvokeBodyTag.doTag(InvokeBodyTag.java:91)
      at org.apache.commons.jelly.impl.TagScript.run(TagScript.java:269)
      at org.apache.commons.jelly.impl.ScriptBlock.run(ScriptBlock.java:95)
      at org.apache.commons.jelly.TagSupport.invokeBody(TagSupport.java:161)
      at org.apache.commons.jelly.tags.core.OtherwiseTag.doTag(OtherwiseTag.java:41)
      at org.apache.commons.jelly.impl.TagScript.run(TagScript.java:269)
      at org.apache.commons.jelly.impl.ScriptBlock.run(ScriptBlock.java:95)
      at org.apache.commons.jelly.TagSupport.invokeBody(TagSupport.java:161)
      at org.apache.commons.jelly.tags.core.ChooseTag.doTag(ChooseTag.java:38)
      at org.apache.commons.jelly.impl.TagScript.run(TagScript.java:269)
      at org.apache.commons.jelly.tags.core.CoreTagLibrary$2.run(CoreTagLibrary.java:105)
      at org.kohsuke.stapler.jelly.CallTagLibScript.run(CallTagLibScript.java:119)
      at org.apache.commons.jelly.tags.core.CoreTagLibrary$2.run(CoreTagLibrary.java:105)
      at org.kohsuke.stapler.jelly.JellyViewScript.run(JellyViewScript.java:81)
      at org.kohsuke.stapler.jelly.DefaultScriptInvoker.invokeScript(DefaultScriptInvoker.java:63)
      at org.kohsuke.stapler.jelly.DefaultScriptInvoker.invokeScript(DefaultScriptInvoker.java:53)
      at org.kohsuke.stapler.jelly.JellyFacet$1.dispatch(JellyFacet.java:95)
      ... 69 more
      Caused by: java.lang.IllegalArgumentException: Comparison method violates its general contract!
      at java.util.TimSort.mergeLo(TimSort.java:747)
      at java.util.TimSort.mergeAt(TimSort.java:483)
      at java.util.TimSort.mergeCollapse(TimSort.java:410)
      at java.util.TimSort.sort(TimSort.java:214)
      at java.util.TimSort.sort(TimSort.java:173)
      at java.util.Arrays.sort(Arrays.java:659)
      at java.util.Collections.sort(Collections.java:217)
      at maps.hudson.plugin.xfpanel.XFPanelView.sort(XFPanelView.java:374)
      at sun.reflect.GeneratedMethodAccessor2240.invoke(Unknown Source)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:601)
      at org.apache.commons.beanutils.MethodUtils.invokeMethod(MethodUtils.java:282)
      at org.apache.commons.jelly.tags.core.InvokeTag.doTag(InvokeTag.java:97)
      ... 102 more

          [JENKINS-20768] Comparison method violates its general contract exception

          Tobias Tobiasen added a comment - A workaround is to add "-Djava.util.Arrays.useLegacyMergeSort=true" to the JVM at startup. See http://stackoverflow.com/questions/7849539/comparison-method-violates-its-general-contract-java-7-only http://stackoverflow.com/questions/15893487/compile-in-java-6-run-in-7-how-to-specify-uselegacymergesort

          Tomasz Bech added a comment -

          This new algorithm with throwing exception is pretty nasty: sorting violatile data will most likely throw exception. Here
          during sort the 'status' of the job can change so even having perfect comparison sort can fail.

          Simple test below which simulates that data used in sort changes 'outside' - fails most of the time.

          public void testSort2() {
          List<A> list = new ArrayList<A>();
          for (int i = 0; i < 1000; i++)

          { A a1 = new A(); a1.setValue((int) (Math.random() * 100)); list.add(a1); }

          Collections.sort(list, new Comparator<A>() {

          @Override
          public int compare(A o1, A o2) {
          o2.setValue((int) (Math.random() * 100)); //HERE value has changed 'outside'
          if (o1.getValue() > o2.getValue())

          { return 1; }

          if (o1.getValue() < o2.getValue())

          { return -1; }

          return 0;
          }
          });
          }

          So to make it 100% we should have collect all values before sort (priority, lastBuild, isBuilding, CompletionTimestamp) - not worth much such refactoring.

          I suggest to stick with '-Djava.util.Arrays.useLegacyMergeSort=true'

          Tomasz Bech added a comment - This new algorithm with throwing exception is pretty nasty: sorting violatile data will most likely throw exception. Here during sort the 'status' of the job can change so even having perfect comparison sort can fail. Simple test below which simulates that data used in sort changes 'outside' - fails most of the time. public void testSort2() { List<A> list = new ArrayList<A>(); for (int i = 0; i < 1000; i++) { A a1 = new A(); a1.setValue((int) (Math.random() * 100)); list.add(a1); } Collections.sort(list, new Comparator<A>() { @Override public int compare(A o1, A o2) { o2.setValue((int) (Math.random() * 100)); //HERE value has changed 'outside' if (o1.getValue() > o2.getValue()) { return 1; } if (o1.getValue() < o2.getValue()) { return -1; } return 0; } }); } So to make it 100% we should have collect all values before sort (priority, lastBuild, isBuilding, CompletionTimestamp) - not worth much such refactoring. I suggest to stick with '-Djava.util.Arrays.useLegacyMergeSort=true'

            tomaszbech Tomasz Bech
            tobiasen Tobias Tobiasen
            Votes:
            1 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated: