CXF
  1. CXF
  2. CXF-4534

SortedMap is returned as HashMap

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 2.6.2, 2.7.0
    • Fix Version/s: 2.6.3, 2.7.0
    • Component/s: Aegis Databinding
    • Labels:
      None
    • Environment:

      debian wheezy/testing, unstable

    • Estimated Complexity:
      Unknown

      Description

      We have recently upgraded to 2.6.2 and revisit our test suite. Looks like all bugs submitted by use have been fixed. Very impressive, thanks a lot.

      In our test suite there is a bug that has not been submitted in JIRA. A discussion about that bug can be found at

      http://comments.gmane.org/gmane.comp.apache.cxf.user/12388

      I decided to submit this bug anyway for documentation purposes.

      The problem:
      ------------

      The problem is when the interface declares a SortedMap as an argument or as a returned value. Here is the relevant snippets.

      Interface
      ---------

          // fail -- throws exception in the server
          public boolean testSortedMapArgument(SortedMap<Integer, Integer> map);
      
          // fail -- puts data into a hashmap instead of a SortedMap
          public SortedMap<Integer, Integer> testSortedMapResult();
      
          // fail -- puts data into a hashmap instead of a SortedMap
          public Map<String, SortedMap<Integer, Integer>> testDirectComplexTreeMapResult();
      

      Implementation
      --------------

          @Override
          public boolean testSortedMapArgument(SortedMap<Integer, Integer> map) {
              final Class map_class = map.getClass();
              final Collection<Class> klasses = Arrays.asList(map_class.getClasses());
              log.info(String.format("Classes of %s are %s", map_class, klasses));
              return klasses.contains(SortedMap.class);
          }
      
          @Override
          public SortedMap<Integer, Integer> testSortedMapResult() {
              final SortedMap<Integer, Integer> result = new TreeMap<Integer, Integer>();
              result.put(1, 3);
              result.put(0, 2);
              return result;
          }
      
          @Override
          public Map<String, SortedMap<Integer, Integer>> testDirectComplexTreeMapResult() {
              final Map<String, SortedMap<Integer, Integer>> result = new HashMap<String, SortedMap<Integer, Integer>>();
              final TreeMap<Integer, Integer> map1 = new TreeMap<Integer, Integer>();
              map1.put(1, 3);
              map1.put(0, 2);
              result.put("key1", map1);
              return result;
          }
      

      Test Client:
      ------------

          @Test
          public void testSortedMapArgument() {
              final SortedMap<Integer, Integer> map = new TreeMap<Integer, Integer>();
              map.put(1, 3);
              map.put(0, 2);
              Assert.assertTrue(TestServiceFactory.getService()
                      .testSortedMapArgument(map));
          }
      
          @Test
          public void testSortedMapResult() {
              final Class map_class = ((Object) TestServiceFactory.getService()
                      .testDirectComplexTreeMapResult()).getClass();
              final Collection<Class> klasses = Arrays.asList(map_class.getClasses());
              log.info(String.format("Classes of %s are %s", map_class, klasses));
              Assert.assertTrue(klasses.contains(SortedMap.class));
          }
      
          @Test
          public void testDirectComplexTreeMapResult() {
              final Class map_class = ((Object) TestServiceFactory.getService()
                      .testDirectComplexTreeMapResult().get("key1")).getClass();
              final Collection<Class> klasses = Arrays.asList(map_class.getClasses());
              log.info(String.format("Classes of %s are %s", map_class, klasses));
              Assert.assertTrue(klasses.contains(SortedMap.class));
          }
      

      The result:
      -----------

      In cases 2 and 3 I get a hashmap instead of a SortedMap. This is very dangerous since it changes program semantics in a very subtle way.

      In case 1 I get an exception. Here is the server side part:

      WARNING: Application {http://iface/}TestInterface#{http://iface/}testSortedMapArgument has thrown exception, unwinding now
      org.apache.cxf.interceptor.Fault: argument type mismatch while invoking public abstract boolean iface.TestInterface.testSortedMapArgument(java.util.SortedMap) with params [{0=2, 1=3}].
              at org.apache.cxf.service.invoker.AbstractInvoker.createFault(AbstractInvoker.java:166)
              at org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:140)
              at org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:75)
              at org.apache.cxf.interceptor.ServiceInvokerInterceptor$1.run(ServiceInvokerInterceptor.java:58)
              at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
              at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
              at java.util.concurrent.FutureTask.run(FutureTask.java:166)
              at org.apache.cxf.workqueue.SynchronousExecutor.execute(SynchronousExecutor.java:37)
              at org.apache.cxf.interceptor.ServiceInvokerInterceptor.handleMessage(ServiceInvokerInterceptor.java:107)
              at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:262)
              at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121)
              at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:211)
              at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:213)
              at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:193)
              at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:130)
              at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:221)
              at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doPost(AbstractHTTPServlet.java:141)
              at javax.servlet.http.HttpServlet.service(HttpServlet.java:641)
              at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:197)
              at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
              at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
              at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:225)
              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:168)
              at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
              at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927)
              at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
              at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
              at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1001)
              at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:579)
              at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
              at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
              at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
              at java.lang.Thread.run(Thread.java:722)
      Caused by: java.lang.IllegalArgumentException: argument type mismatch
              at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
              at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
              at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
              at java.lang.reflect.Method.invoke(Method.java:601)
              at org.apache.cxf.service.invoker.AbstractInvoker.performInvocation(AbstractInvoker.java:180)
              at org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:96)
              ... 33 more
      

      Expected result:
      ----------------

      To safely transfer a SortedMap both ways.

      I would understand if due to WSDL constraints reliably transferring a sortedMap is not possible. What it would be nice is at least during the deploy time an error / warning is issued stating that fact.

      Right now we are getting incorrect results in a silent way or a the best case an exception at run time.

      1. ws-test-issue-4534.tgz
        9 kB
        Vassilis Virvilis

        Activity

        Hide
        Daniel Kulp added a comment -


        This should now be fixed. It would be great if you could verify with tomorrows snapshots.

        Show
        Daniel Kulp added a comment - This should now be fixed. It would be great if you could verify with tomorrows snapshots.
        Hide
        Vassilis Virvilis added a comment -

        I tried with apache-cxf-2.6.3-20121005.080754-29.tar.gz and all 3 problems persist.

        Should I try with 2.7.0 snapshot?

        Vassilis

        Show
        Vassilis Virvilis added a comment - I tried with apache-cxf-2.6.3-20121005.080754-29.tar.gz and all 3 problems persist. Should I try with 2.7.0 snapshot? Vassilis
        Hide
        Vassilis Virvilis added a comment -

        The fix is supposed to be applied at 2.6.3 but it still does not work for me. Tested with apache-cxf-2.6.3-20121005.080754-29.tar.gz in both server and client.

        Hence I am reopening the bug...

        If I shouldn't do this please let me know since I am not fully familiarized with CXF bug-etiquette.

        Could you also please tell us what is the expected behaviour? Normal transmission of SortedMap or some kind of error / warning? Anyway I didn't get any errors warnings during deploy...

        Thanks

        Show
        Vassilis Virvilis added a comment - The fix is supposed to be applied at 2.6.3 but it still does not work for me. Tested with apache-cxf-2.6.3-20121005.080754-29.tar.gz in both server and client. Hence I am reopening the bug... If I shouldn't do this please let me know since I am not fully familiarized with CXF bug-etiquette. Could you also please tell us what is the expected behaviour? Normal transmission of SortedMap or some kind of error / warning? Anyway I didn't get any errors warnings during deploy... Thanks
        Hide
        Vassilis Virvilis added a comment -

        The fix is supposed to be applied at 2.6.3 but it still does not work for me. Tested with apache-cxf-2.6.3-20121005.080754-29.tar.gz in both server and client.

        Hence I am reopening the bug...

        If I shouldn't do this please let me know since I am not fully familiarized with CXF bug-etiquette.

        Could you also please tell us what is the expected behaviour? Normal transmission of SortedMap or some kind of error / warning? Anyway I didn't get any errors warnings during deploy...

        Thanks

        Show
        Vassilis Virvilis added a comment - The fix is supposed to be applied at 2.6.3 but it still does not work for me. Tested with apache-cxf-2.6.3-20121005.080754-29.tar.gz in both server and client. Hence I am reopening the bug... If I shouldn't do this please let me know since I am not fully familiarized with CXF bug-etiquette. Could you also please tell us what is the expected behaviour? Normal transmission of SortedMap or some kind of error / warning? Anyway I didn't get any errors warnings during deploy... Thanks
        Hide
        Vassilis Virvilis added a comment -

        I also tested it with 2.7.0

        Show
        Vassilis Virvilis added a comment - I also tested it with 2.7.0
        Hide
        Daniel Kulp added a comment -

        Any chance you can create a simple and small complete test case?

        Show
        Daniel Kulp added a comment - Any chance you can create a simple and small complete test case?
        Hide
        Vassilis Virvilis added a comment -

        Sure why not? Here is the test case. I have not included necessary third party libraries. The project requires

        cxf-libraries
        log4j
        commons-logging
        junit

        After that you do
        ant war
        and the war will be created.

        The TestClient will try to connect at localhost:8080 by default

        Thanks

        Show
        Vassilis Virvilis added a comment - Sure why not? Here is the test case. I have not included necessary third party libraries. The project requires cxf-libraries log4j commons-logging junit After that you do ant war and the war will be created. The TestClient will try to connect at localhost:8080 by default Thanks
        Hide
        Daniel Kulp added a comment -

        The testcase is not valid. The call to cls.getClasses() is returning the internal classes, not the interfaces and such. If you actually look at the output, you see:

        Classes of class java.util.TreeMap are [class java.util.AbstractMap$SimpleImmutableEntry, class java.util.AbstractMap$SimpleEntry]
        

        so it is indeed creating a TreeMap (which implements SortedMap). If you just take the return maps and do a:

        Assert.assertTrue(ret instanceof SortedMap);
        

        then you would see that the values really are the sorted maps that are expected.

        Show
        Daniel Kulp added a comment - The testcase is not valid. The call to cls.getClasses() is returning the internal classes, not the interfaces and such. If you actually look at the output, you see: Classes of class java.util.TreeMap are [class java.util.AbstractMap$SimpleImmutableEntry, class java.util.AbstractMap$SimpleEntry] so it is indeed creating a TreeMap (which implements SortedMap). If you just take the return maps and do a: Assert.assertTrue(ret instanceof SortedMap); then you would see that the values really are the sorted maps that are expected.
        Hide
        Vassilis Virvilis added a comment -

        Aah. I agree. I was fooled by my own tests.

        I can confirm that the mini test case now works.

        Show
        Vassilis Virvilis added a comment - Aah. I agree. I was fooled by my own tests. I can confirm that the mini test case now works.

          People

          • Assignee:
            Daniel Kulp
            Reporter:
            Vassilis Virvilis
          • Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development