You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by se...@apache.org on 2009/04/08 12:54:55 UTC

svn commit: r763176 - in /cxf/trunk/rt/frontend/jaxrs/src: main/java/org/apache/cxf/jaxrs/utils/InjectionUtils.java test/java/org/apache/cxf/jaxrs/Customer.java test/java/org/apache/cxf/jaxrs/utils/JAXRSUtilsTest.java

Author: sergeyb
Date: Wed Apr  8 10:54:54 2009
New Revision: 763176

URL: http://svn.apache.org/viewvc?rev=763176&view=rev
Log:
CXF-2153 : applying a patch on behalf of Craig Muchinsky

Modified:
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/InjectionUtils.java
    cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/Customer.java
    cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/utils/JAXRSUtilsTest.java

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/InjectionUtils.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/InjectionUtils.java?rev=763176&r1=763175&r2=763176&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/InjectionUtils.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/InjectionUtils.java Wed Apr  8 10:54:54 2009
@@ -31,7 +31,9 @@
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -62,6 +64,7 @@
 import org.apache.cxf.common.util.PrimitiveUtils;
 import org.apache.cxf.jaxrs.ext.MessageContext;
 import org.apache.cxf.jaxrs.ext.ParameterHandler;
+import org.apache.cxf.jaxrs.impl.MetadataMap;
 import org.apache.cxf.jaxrs.impl.PathSegmentImpl;
 import org.apache.cxf.jaxrs.impl.tl.ThreadLocalContextResolver;
 import org.apache.cxf.jaxrs.impl.tl.ThreadLocalHttpHeaders;
@@ -133,6 +136,23 @@
         });
         
     }
+
+    @SuppressWarnings("unchecked")
+    public static Object extractFieldValue(final Field f, 
+                                        final Object o) {
+        return AccessController.doPrivileged(new PrivilegedAction() {
+            public Object run() {
+                f.setAccessible(true);
+                try {
+                    return f.get(o);
+                } catch (IllegalAccessException ex) {
+                    reportServerError("FIELD_ACCESS_FAILURE", 
+                                      f.getType().getName());
+                }
+                return null;
+            }
+        });
+    }
     
     public static Class<?> getActualType(Type genericType) {
         
@@ -168,6 +188,19 @@
             reportServerError("METHOD_INJECTION_FAILURE", method.getName());
         }
     }
+
+    public static Object extractFromMethod(Object requestObject,
+                                           Method method) {
+        try {
+            Method methodToInvoke = checkProxy(method, requestObject);
+            return methodToInvoke.invoke(requestObject);
+        } catch (IllegalAccessException ex) {
+            reportServerError("METHOD_ACCESS_FAILURE", method.getName());
+        } catch (Exception ex) {
+            reportServerError("METHOD_INJECTION_FAILURE", method.getName());
+        }
+        return null;
+    }
     
     public static Object handleParameter(String value, 
                                          Class<?> pClass, 
@@ -275,90 +308,250 @@
             reportServerError("CLASS_INSTANTIATION_FAILURE", paramType.getName());
         }    
         
+        Map<String, MultivaluedMap<String, String>> parsedValues =
+            new HashMap<String, MultivaluedMap<String, String>>();
         for (Map.Entry<String, List<String>> entry : values.entrySet()) {
-            boolean injected = false;
-            for (Method m : paramType.getMethods()) {
-                if (m.getName().equalsIgnoreCase("set" + entry.getKey())
-                    && m.getParameterTypes().length == 1) {
-                    Object paramValue = handleParameter(entry.getValue().get(0), 
-                                                        m.getParameterTypes()[0],
-                                                        pType, message);
-                    if (paramValue != null) {
-                        injectThroughMethod(bean, m, paramValue);
-                        injected = true;
-                        break;
-                    }
-                }
+            String memberKey = entry.getKey();
+            String beanKey = null;
+
+            int idx = memberKey.indexOf('.');
+            if (idx == -1) {
+                beanKey = "." + memberKey;
+            } else {
+                beanKey = memberKey.substring(0, idx);
+                memberKey = memberKey.substring(idx + 1);
             }
-            if (injected) {
-                continue;
+
+            MultivaluedMap<String, String> value = parsedValues.get(beanKey);
+            if (value == null) {
+                value = new MetadataMap<String, String>();
+                parsedValues.put(beanKey, value);
             }
-            for (Field f : paramType.getFields()) {
-                if (f.getName().equalsIgnoreCase(entry.getKey())) {
-                    Object paramValue = handleParameter(entry.getValue().get(0), 
-                                                        f.getType(), pType, message);
-                    if (paramValue != null) {
-                        injectFieldValue(f, bean, paramValue);
+            value.put(memberKey, entry.getValue());
+        }
+
+        if (parsedValues.size() > 0) {
+            for (Map.Entry<String, MultivaluedMap<String, String>> entry : parsedValues.entrySet()) {
+                String memberKey = entry.getKey();
+
+                boolean isbean = !memberKey.startsWith(".");
+                if (!isbean) {
+                    memberKey = memberKey.substring(1);
+                }
+
+                Object setter = null;
+                Object getter = null;
+                for (Method m : paramType.getMethods()) {
+                    if (m.getName().equalsIgnoreCase("set" + memberKey)
+                        && m.getParameterTypes().length == 1) {
+                        setter = m;
+                    } else if (m.getName().equalsIgnoreCase("get" + memberKey)
+                        && m.getReturnType() != Void.TYPE) {
+                        getter = m;
+                    }
+                    if (setter != null && getter != null) {
                         break;
                     }
                 }
+                if (setter == null) {
+                    for (Field f : paramType.getFields()) {
+                        if (f.getName().equalsIgnoreCase(memberKey)) {
+                            setter = f;
+                            getter = f;
+                            break;
+                        }
+                    }
+                }
+
+                if (setter != null && getter != null) {
+                    Class<?> type = null;
+                    Type genericType = null;
+                    Object paramValue = null;
+                    if (setter instanceof Method) {
+                        type = Method.class.cast(setter).getParameterTypes()[0];
+                        genericType = Method.class.cast(setter).getGenericParameterTypes()[0];
+                        paramValue = InjectionUtils.extractFromMethod(bean, (Method) getter);
+                    } else {
+                        type = Field.class.cast(setter).getType();
+                        genericType = Field.class.cast(setter).getGenericType();
+                        paramValue = InjectionUtils.extractFieldValue((Field) getter, bean);
+                    }
+
+                    List<MultivaluedMap<String, String>> processedValuesList =
+                        processValues(type, genericType, entry.getValue(), isbean);
+
+                    for (MultivaluedMap<String, String> processedValues : processedValuesList) {
+                        if (InjectionUtils.isSupportedCollectionOrArray(type)) {
+                            Object appendValue = InjectionUtils.injectIntoCollectionOrArray(type,
+                                                            genericType, processedValues,
+                                                            isbean, true,
+                                                            pType, message);
+                            paramValue = InjectionUtils.mergeCollectionsOrArrays(paramValue, appendValue,
+                                                            genericType);
+                        } else if (isbean) {
+                            paramValue = InjectionUtils.handleBean(type, processedValues,
+                                                            pType, message);
+                        } else {
+                            paramValue = InjectionUtils.handleParameter(
+                                                            processedValues.values().iterator().next().get(0),
+                                                            type,
+                                                            pType, message);
+                        }
+
+                        if (paramValue != null) {
+                            if (setter instanceof Method) {
+                                InjectionUtils.injectThroughMethod(bean, (Method) setter, paramValue);
+                            } else {
+                                InjectionUtils.injectFieldValue((Field) setter, bean, paramValue);
+                            }
+                        }
+                    }
+                }
             }
         }
         
         return bean;
     }
-    
-    @SuppressWarnings("unchecked")
-    public static Object injectIntoList(Type genericType, List<String> values,
-                                        boolean decoded, ParameterType pathParam, Message message) {
-        Class<?> realType = InjectionUtils.getActualType(genericType);
-        values = checkPathSegment(values, realType, pathParam);
-        List theValues = new ArrayList();
-        for (String r : values) {
-            String value = decodeValue(r, decoded, pathParam);
-            
-            Object o = InjectionUtils.handleParameter(value, realType, pathParam, message);
-            if (o != null) {
-                theValues.add(o);
+
+    private static List<MultivaluedMap<String, String>> processValues(Class<?> type, Type genericType,
+                                        MultivaluedMap<String, String> values,
+                                        boolean isbean) {
+        List<MultivaluedMap<String, String>> valuesList =
+            new ArrayList<MultivaluedMap<String, String>>();
+
+        if (isbean && InjectionUtils.isSupportedCollectionOrArray(type)) {
+            Class<?> realType = InjectionUtils.getActualType(genericType);
+            for (Map.Entry<String, List<String>> entry : values.entrySet()) {
+                String memberKey = entry.getKey();
+                Class<?> memberType = null;
+
+                for (Method m : realType.getMethods()) {
+                    if (m.getName().equalsIgnoreCase("set" + memberKey)
+                        && m.getParameterTypes().length == 1) {
+                        memberType = m.getParameterTypes()[0];
+                        break;
+                    }
+                }
+                if (memberType == null) {
+                    for (Field f : realType.getFields()) {
+                        if (f.getName().equalsIgnoreCase(memberKey)) {
+                            memberType = f.getType();
+                            break;
+                        }
+                    }
+                }
+
+                // Strip values tied to collection/array fields from beans that are within
+                // collection/array themselves, the only way to support this would be to have
+                // an indexing syntax for nested beans, perhaps like this:
+                //    a(0).b=1&a(0).b=2&a(1).b=3&a(1).b=4
+                // For now though we simply don't support this capability. To illustrate, the 'c'
+                // param is dropped from this multivaluedmap example since it is a list:
+                //    {c=[71, 81, 91, 72, 82, 92], a=[C1, C2], b=[790, 791]}
+                if (memberType != null && InjectionUtils.isSupportedCollectionOrArray(memberType)) {
+                    continue;
+                }
+
+                // Split multivaluedmap value list contents into separate multivaluedmap instances
+                // whose list contents are only 1 level deep, for example: 
+                //    {a=[C1, C2], b=[790, 791]}
+                // becomes these 2 separate multivaluedmap instances:
+                //    {a=[C1], b=[790]} and {a=[C2], b=[791]}
+                int idx = 0;
+                for (String value : entry.getValue()) {
+                    MultivaluedMap<String, String> splitValues =
+                        (idx < valuesList.size()) ? valuesList.get(idx) : null;
+                    if (splitValues == null) {
+                        splitValues = new MetadataMap<String, String>();
+                        valuesList.add(splitValues);
+                    }
+                    splitValues.add(memberKey, value);
+                    idx++;
+                }
             }
+        } else {
+            valuesList.add(values);
         }
-        return theValues;
+
+        return valuesList;
     }
-    
-    public static Object injectIntoArray(Type genericType, List<String> values,
-                                         boolean decoded, ParameterType pathParam, Message message) {
+
+    public static boolean isSupportedCollectionOrArray(Class<?> type) {
+        return List.class.isAssignableFrom(type)
+            || Set.class.isAssignableFrom(type)
+            || SortedSet.class.isAssignableFrom(type)
+            || type.isArray();
+    }
+
+    @SuppressWarnings("unchecked")
+    private static Object mergeCollectionsOrArrays(Object first, Object second, Type genericType) {
+        if (first == null) {
+            return second;
+        } else if (first instanceof Collection) {
+            Collection.class.cast(first).addAll((Collection) second);
+            return first;
+        } else {
+            int firstLen = Array.getLength(first);
+            int secondLen = Array.getLength(second);
+            Object mergedArray = Array.newInstance(InjectionUtils.getActualType(genericType),
+                                                    firstLen + secondLen);
+            System.arraycopy(first, 0, mergedArray, 0, firstLen);
+            System.arraycopy(second, 0, mergedArray, firstLen, secondLen);
+            return mergedArray;
+        }
+    }
+
+    private static Object injectIntoCollectionOrArray(Class<?> rawType, Type genericType,
+                                        MultivaluedMap<String, String> values,
+                                        boolean isbean, boolean decoded,
+                                        ParameterType pathParam, Message message) {
+        Class<?> type = null;
+        if (List.class.isAssignableFrom(rawType)) {
+            type = ArrayList.class;
+        } else if (Set.class.isAssignableFrom(rawType)) {
+            type = HashSet.class;
+        } else if (SortedSet.class.isAssignableFrom(rawType)) {
+            type = TreeSet.class;
+        }
+
         Class<?> realType = InjectionUtils.getActualType(genericType);
-        values = checkPathSegment(values, realType, pathParam);
-        Object[] array = (Object[])Array.newInstance(realType, values.size());
-        for (int i = 0; i < values.size(); i++) {
-            String value = decodeValue(values.get(i), decoded, pathParam);
-            Object o = InjectionUtils.handleParameter(value, realType, pathParam, message);
-            if (o != null) {
-                array[i] = o;
+        
+        Object theValues = null;
+        if (type != null) {
+            try {
+                theValues = type.newInstance();
+            } catch (IllegalAccessException ex) {
+                reportServerError("CLASS_ACCESS_FAILURE", type.getName());
+            } catch (Exception ex) {
+                reportServerError("CLASS_INSTANTIATION_FAILURE", type.getName());
+            }
+        } else {
+            theValues = Array.newInstance(realType, isbean ? 1 : values.values().iterator().next().size());
+        }
+        if (isbean) {
+            Object o = InjectionUtils.handleBean(realType, values, pathParam, message);
+            addToCollectionValues(theValues, o, 0);
+        } else {
+            List<String> valuesList = values.values().iterator().next();
+            valuesList = checkPathSegment(valuesList, realType, pathParam);
+            for (int ind = 0; ind < valuesList.size(); ind++) {
+                String value = decodeValue(valuesList.get(ind), decoded, pathParam);
+                Object o = InjectionUtils.handleParameter(value, realType, pathParam, message);
+                addToCollectionValues(theValues, o, ind);
             }
         }
-        return array;
+        return theValues;
     }
     
-    
     @SuppressWarnings("unchecked")
-    public static Object injectIntoSet(Type genericType, List<String> values, 
-                                       boolean sorted, 
-                                       boolean decoded, 
-                                       ParameterType pathParam, Message message) {
-        Class<?> realType = InjectionUtils.getActualType(genericType);
-        
-        values = checkPathSegment(values, realType, pathParam);
-        
-        Set theValues = sorted ? new TreeSet() : new HashSet();
-        for (String r : values) {
-            String value = decodeValue(r, decoded, pathParam);
-            Object o = InjectionUtils.handleParameter(value, realType, pathParam, message);
-            if (o != null) {
-                theValues.add(o);
+    private static void addToCollectionValues(Object theValues, Object o, int index) {
+        if (o != null) {
+            if (theValues instanceof Collection) {
+                Collection.class.cast(theValues).add(o);
+            } else {
+                ((Object[]) theValues)[index] = o;
             }
         }
-        return theValues;
     }
     
     private static List<String> checkPathSegment(List<String> values, Class<?> type, 
@@ -403,17 +596,11 @@
         }
 
         Object value = null;
-        if (List.class.isAssignableFrom(paramType)) {
-            value = InjectionUtils.injectIntoList(genericType, paramValues, decoded, pathParam,
-                                                 message);
-        } else if (Set.class.isAssignableFrom(paramType)) {
-            value = InjectionUtils.injectIntoSet(genericType, paramValues, false, decoded, pathParam,
-                                                message);
-        } else if (SortedSet.class.isAssignableFrom(paramType)) {
-            value = InjectionUtils.injectIntoSet(genericType, paramValues, true, decoded, pathParam,
-                                                message);
-        } else if (paramType.isArray()) {
-            value = InjectionUtils.injectIntoArray(genericType, paramValues, decoded, pathParam, message);
+        if (InjectionUtils.isSupportedCollectionOrArray(paramType)) {
+            MultivaluedMap<String, String> paramValuesMap = new MetadataMap<String, String>();
+            paramValuesMap.put("", paramValues);
+            value = InjectionUtils.injectIntoCollectionOrArray(paramType, genericType, paramValuesMap,
+                                                false, decoded, pathParam, message);
         } else {
             String result = null;
             if (paramValues.size() > 0) {

Modified: cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/Customer.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/Customer.java?rev=763176&r1=763175&r2=763176&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/Customer.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/Customer.java Wed Apr  8 10:54:54 2009
@@ -55,18 +55,35 @@
     public static class CustomerBean {
         private String a;
         private Long b;
+        private List<String> c;
+        private CustomerBean d;
+        //CHECKSTYLE:OFF
+        public List<CustomerBean> e;
+        //CHECKSTYLE:ON
         public void setA(String aString) {
             this.a = aString;
         }
         public void setB(Long bLong) {
             this.b = bLong;
         }
+        public void setC(List<String> cStringList) {
+            this.c = cStringList;
+        }
+        public void setD(CustomerBean dCustomerBean) {
+            this.d = dCustomerBean;
+        }
         public String getA() {
             return a;
         }
         public Long getB() {
             return b;
         }
+        public List<String> getC() {
+            return c;
+        }
+        public CustomerBean getD() {
+            return d;
+        }
         
     }
     

Modified: cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/utils/JAXRSUtilsTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/utils/JAXRSUtilsTest.java?rev=763176&r1=763175&r2=763176&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/utils/JAXRSUtilsTest.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/utils/JAXRSUtilsTest.java Wed Apr  8 10:54:54 2009
@@ -630,37 +630,73 @@
         Class[] argType = {Customer.CustomerBean.class};
         Method m = Customer.class.getMethod("testQueryBean", argType);
         MessageImpl messageImpl = new MessageImpl();
-        
         messageImpl.put(Message.QUERY_STRING, "a=aValue&b=123");
-        List<Object> params = JAXRSUtils.processParameters(new OperationResourceInfo(m, null),
-                                                           null, 
-                                                           messageImpl);
-        assertEquals("Bean should be created", 1, params.size());
-        Customer.CustomerBean cb = (Customer.CustomerBean)params.get(0);
-        assertNotNull(cb);
-        
-        assertEquals("aValue", cb.getA());
-        assertEquals(new Long(123), cb.getB());
+
+        MessageImpl complexMessageImpl = new MessageImpl();
+        complexMessageImpl.put(Message.QUERY_STRING, "c=1&a=A&b=123&c=2&c=3&"
+                                + "d.c=4&d.a=B&d.b=456&d.c=5&d.c=6&"
+                                + "e.c=41&e.a=B1&e.b=457&e.c=51&e.c=61&"
+                                + "e.c=42&e.a=B2&e.b=458&e.c=52&e.c=62&"
+                                + "d.d.c=7&d.d.a=C&d.d.b=789&d.d.c=8&d.d.c=9&"
+                                + "d.e.c=71&d.e.a=C1&d.e.b=790&d.e.c=81&d.e.c=91&"
+                                + "d.e.c=72&d.e.a=C2&d.e.b=791&d.e.c=82&d.e.c=92");
+
+        verifyParametersBean(m, null, messageImpl, null, complexMessageImpl);
     }
     
     @Test
     public void testPathParametersBean() throws Exception {
         Class[] argType = {Customer.CustomerBean.class};
         Method m = Customer.class.getMethod("testPathBean", argType);
-        MessageImpl messageImpl = new MessageImpl();
-        
-        MultivaluedMap<String, String> pathTamplates = new MetadataMap<String, String>();
-        pathTamplates.add("a", "aValue");
-        pathTamplates.add("b", "123");
-        List<Object> params = JAXRSUtils.processParameters(new OperationResourceInfo(m, null),
-                                                           pathTamplates, 
-                                                           messageImpl);
-        assertEquals("Bean should be created", 1, params.size());
-        Customer.CustomerBean cb = (Customer.CustomerBean)params.get(0);
-        assertNotNull(cb);
         
-        assertEquals("aValue", cb.getA());
-        assertEquals(new Long(123), cb.getB());
+        MultivaluedMap<String, String> pathTemplates = new MetadataMap<String, String>();
+        pathTemplates.add("a", "aValue");
+        pathTemplates.add("b", "123");
+
+        MultivaluedMap<String, String> complexPathTemplates = new MetadataMap<String, String>();
+        complexPathTemplates.add("c", "1");
+        complexPathTemplates.add("a", "A");
+        complexPathTemplates.add("b", "123");
+        complexPathTemplates.add("c", "2");
+        complexPathTemplates.add("c", "3");
+
+        complexPathTemplates.add("d.c", "4");
+        complexPathTemplates.add("d.a", "B");
+        complexPathTemplates.add("d.b", "456");
+        complexPathTemplates.add("d.c", "5");
+        complexPathTemplates.add("d.c", "6");
+
+        complexPathTemplates.add("e.c", "41");
+        complexPathTemplates.add("e.a", "B1");
+        complexPathTemplates.add("e.b", "457");
+        complexPathTemplates.add("e.c", "51");
+        complexPathTemplates.add("e.c", "61");
+
+        complexPathTemplates.add("e.c", "42");
+        complexPathTemplates.add("e.a", "B2");
+        complexPathTemplates.add("e.b", "458");
+        complexPathTemplates.add("e.c", "52");
+        complexPathTemplates.add("e.c", "62");
+
+        complexPathTemplates.add("d.d.c", "7");
+        complexPathTemplates.add("d.d.a", "C");
+        complexPathTemplates.add("d.d.b", "789");
+        complexPathTemplates.add("d.d.c", "8");
+        complexPathTemplates.add("d.d.c", "9");
+
+        complexPathTemplates.add("d.e.c", "71");
+        complexPathTemplates.add("d.e.a", "C1");
+        complexPathTemplates.add("d.e.b", "790");
+        complexPathTemplates.add("d.e.c", "81");
+        complexPathTemplates.add("d.e.c", "91");
+
+        complexPathTemplates.add("d.e.c", "72");
+        complexPathTemplates.add("d.e.a", "C2");
+        complexPathTemplates.add("d.e.b", "791");
+        complexPathTemplates.add("d.e.c", "82");
+        complexPathTemplates.add("d.e.c", "92");
+
+        verifyParametersBean(m, pathTemplates, new MessageImpl(), complexPathTemplates, new MessageImpl());
     }
     
     @Test
@@ -669,15 +705,17 @@
         Method m = Customer.class.getMethod("testMatrixBean", argType);
         MessageImpl messageImpl = new MessageImpl();
         messageImpl.put(Message.REQUEST_URI, "/bar;a=aValue/baz;b=123");
-        List<Object> params = JAXRSUtils.processParameters(new OperationResourceInfo(m, null),
-                                                           new MetadataMap<String, String>(), 
-                                                           messageImpl);
-        assertEquals("Bean should be created", 1, params.size());
-        Customer.CustomerBean cb = (Customer.CustomerBean)params.get(0);
-        assertNotNull(cb);
-        
-        assertEquals("aValue", cb.getA());
-        assertEquals(new Long(123), cb.getB());
+
+        MessageImpl complexMessageImpl = new MessageImpl();
+        complexMessageImpl.put(Message.REQUEST_URI, "/bar;c=1/bar;a=A/bar;b=123/bar;c=2/bar;c=3"
+                                + "/bar;d.c=4/bar;d.a=B/bar;d.b=456/bar;d.c=5/bar;d.c=6"
+                                + "/bar;e.c=41/bar;e.a=B1/bar;e.b=457/bar;e.c=51/bar;e.c=61"
+                                + "/bar;e.c=42/bar;e.a=B2/bar;e.b=458/bar;e.c=52/bar;e.c=62"
+                                + "/bar;d.d.c=7/bar;d.d.a=C/bar;d.d.b=789/bar;d.d.c=8/bar;d.d.c=9"
+                                + "/bar;d.e.c=71/bar;d.e.a=C1/bar;d.e.b=790/bar;d.e.c=81/bar;d.e.c=91"
+                                + "/bar;d.e.c=72/bar;d.e.a=C2/bar;d.e.b=791/bar;d.e.c=82/bar;d.e.c=92");
+
+        verifyParametersBean(m, null, messageImpl, null, complexMessageImpl);
     }
     
     @Test
@@ -688,15 +726,106 @@
         messageImpl.put(Message.REQUEST_URI, "/bar");
         String body = "a=aValue&b=123";
         messageImpl.setContent(InputStream.class, new ByteArrayInputStream(body.getBytes()));
+
+        MessageImpl complexMessageImpl = new MessageImpl();
+        complexMessageImpl.put(Message.REQUEST_URI, "/bar");
+        body = "c=1&a=A&b=123&c=2&c=3&"
+                                + "d.c=4&d.a=B&d.b=456&d.c=5&d.c=6&"
+                                + "e.c=41&e.a=B1&e.b=457&e.c=51&e.c=61&"
+                                + "e.c=42&e.a=B2&e.b=458&e.c=52&e.c=62&"
+                                + "d.d.c=7&d.d.a=C&d.d.b=789&d.d.c=8&d.d.c=9&"
+                                + "d.e.c=71&d.e.a=C1&d.e.b=790&d.e.c=81&d.e.c=91&"
+                                + "d.e.c=72&d.e.a=C2&d.e.b=791&d.e.c=82&d.e.c=92";
+        complexMessageImpl.setContent(InputStream.class, new ByteArrayInputStream(body.getBytes()));
+
+        verifyParametersBean(m, null, messageImpl, null, complexMessageImpl);
+    }
+
+    private void verifyParametersBean(Method m,
+                                      MultivaluedMap<String, String> simpleValues,
+                                      MessageImpl simpleMessageImpl,
+                                      MultivaluedMap<String, String> complexValues,
+                                      MessageImpl complexMessageImpl) throws Exception {
         List<Object> params = JAXRSUtils.processParameters(new OperationResourceInfo(m, null),
-                                                           new MetadataMap<String, String>(), 
-                                                           messageImpl);
+                                                           simpleValues, 
+                                                           simpleMessageImpl);
         assertEquals("Bean should be created", 1, params.size());
         Customer.CustomerBean cb = (Customer.CustomerBean)params.get(0);
         assertNotNull(cb);
         
         assertEquals("aValue", cb.getA());
         assertEquals(new Long(123), cb.getB());
+
+        params = JAXRSUtils.processParameters(new OperationResourceInfo(m, null),
+                                                       complexValues, 
+                                                       complexMessageImpl);
+        assertEquals("Bean should be created", 1, params.size());
+        Customer.CustomerBean cb1 = (Customer.CustomerBean)params.get(0);
+        assertNotNull(cb1);
+
+        assertEquals("A", cb1.getA());
+        assertEquals(new Long(123), cb1.getB());
+        List<String> list1 = (List<String>)cb1.getC();
+        assertEquals(3, list1.size());
+        assertEquals("1", list1.get(0));
+        assertEquals("2", list1.get(1));
+        assertEquals("3", list1.get(2));
+
+        Customer.CustomerBean cb2 = cb1.getD();
+        assertNotNull(cb2);
+
+        assertEquals("B", cb2.getA());
+        assertEquals(new Long(456), cb2.getB());
+        List<String> list2 = (List<String>)cb2.getC();
+        assertEquals(3, list2.size());
+        assertEquals("4", list2.get(0));
+        assertEquals("5", list2.get(1));
+        assertEquals("6", list2.get(2));
+
+        List<Customer.CustomerBean> cb2List = cb1.e;
+        assertEquals(2, cb2List.size());
+
+        int idx = 1;
+        for (Customer.CustomerBean cb2E : cb2List) {
+            assertNotNull(cb2E);
+
+            assertEquals("B" + idx, cb2E.getA());
+            assertEquals(new Long(456 + idx), cb2E.getB());
+            // ensure C was stripped properly since lists within lists are not supported
+            assertNull(cb2E.getC());
+            assertNull(cb2E.getD());
+            assertNull(cb2E.e);
+
+            idx++;
+        }
+
+        Customer.CustomerBean cb3 = cb2.getD();
+        assertNotNull(cb3);
+
+        assertEquals("C", cb3.getA());
+        assertEquals(new Long(789), cb3.getB());
+        List<String> list3 = (List<String>)cb3.getC();
+        assertEquals(3, list3.size());
+        assertEquals("7", list3.get(0));
+        assertEquals("8", list3.get(1));
+        assertEquals("9", list3.get(2));
+
+        List<Customer.CustomerBean> cb3List = cb2.e;
+        assertEquals(2, cb3List.size());
+
+        idx = 1;
+        for (Customer.CustomerBean cb3E : cb3List) {
+            assertNotNull(cb3E);
+
+            assertEquals("C" + idx, cb3E.getA());
+            assertEquals(new Long(789 + idx), cb3E.getB());
+            // ensure C was stripped properly since lists within lists are not supported
+            assertNull(cb3E.getC());
+            assertNull(cb3E.getD());
+            assertNull(cb3E.e);
+
+            idx++;
+        }
     }
     
     @Test