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

        Vassilis Virvilis created issue -
        Vassilis Virvilis made changes -
        Field Original Value New Value
        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:

            @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));
            }

        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.
        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.
        Daniel Kulp made changes -
        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.
        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
        ---------
        {code:java}
            // 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();
        {code}

        Implementation
        --------------
        {code:java}
            @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;
            }
        {code}

        Test Client:
        ------------
        {code:java}
            @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));
            }
        {code}

        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:
        {code}
        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
        {code}


        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.
        Daniel Kulp made changes -
        Status Open [ 1 ] Resolved [ 5 ]
        Assignee Daniel Kulp [ dkulp ]
        Fix Version/s 2.5.6 [ 12322965 ]
        Fix Version/s 2.6.3 [ 12322964 ]
        Resolution Fixed [ 1 ]
        Vassilis Virvilis made changes -
        Resolution Fixed [ 1 ]
        Status Resolved [ 5 ] Reopened [ 4 ]
        Daniel Kulp made changes -
        Fix Version/s 2.6.3 [ 12322964 ]
        Fix Version/s 2.5.6 [ 12322965 ]
        Vassilis Virvilis made changes -
        Affects Version/s 2.7.0 [ 12321669 ]
        Vassilis Virvilis made changes -
        Attachment ws-test-issue-4534.tgz [ 12549296 ]
        Daniel Kulp made changes -
        Status Reopened [ 4 ] Resolved [ 5 ]
        Fix Version/s 2.7.0 [ 12321669 ]
        Fix Version/s 2.6.3 [ 12322964 ]
        Resolution Fixed [ 1 ]
        Daniel Kulp made changes -
        Status Resolved [ 5 ] Closed [ 6 ]

          People

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

            Dates

            • Created:
              Updated:
              Resolved:

              Development