Uploaded image for project: 'CXF'
  1. CXF
  2. CXF-3149

WebClient getCollection() doesn't work with Jackson's JSON Provider because it passes the wrong types to readFrom()

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Major
    • Resolution: Fixed
    • 2.3
    • 2.3.1, 2.4
    • JAX-RS
    • None

    Description

      When you request a collection from the WebClient it calls readFrom() using the type == Collection.class and the genericType == the member type of the class.

      Unfortunately, this isn't what is normally passed as the genericType when reflection or a GenericEntity was used to write out an object. Normally, the genericType == Collection<X>. In order to be more compatible with third-party providers, it would be best if the generic type was set consistently in each case, rather than having a special case for the collections.

      To support this, the genericType should be set to a subclass of ParameterizedType, for example an instance of this class:

      import java.lang.reflect.ParameterizedType;
      import java.lang.reflect.Type;
      import java.util.Collection;
      
      public final class ParameterizedCollectionType<T> implements ParameterizedType {
      	private final Class<T> collectionMemberClass;
      	private final Type[] typeArgs;
      
      	public ParameterizedCollectionType(Class<T> collectionMemberClass) {
      		this.collectionMemberClass=collectionMemberClass;
      		this.typeArgs=new Type[] { collectionMemberClass };
      	}
      	 
      	public Type[] getActualTypeArguments() {
      	    return typeArgs;
      	}
      
      	public Type getOwnerType() {
      	    return null;
      	}
      
      	public Type getRawType() {
      	    return Collection.class;
      	}
      
      	public String toString() {
      		return "java.util.Collection<"+collectionMemberClass.getName()+">";
      	}
      }
      

      If this class was used in org.apache.cxf.jaxrs.client.WebClient.invokeAndGetCollection(String, Object, Class<T>) then the client would be able to read a JSON collection response using the JacksonJsonProvider.

      As a workaround I have created a subclass of JacksonJsonProvider that "fixes" this issue by overriding readFrom():

      	/**
      	 * For collections, CXF passes type == Collection.class and genericType == the member class type.
      	 * 
      	 * But actually, it should pass genericType = Collection<X> as the generic type in order for Jackson
      	 * to understand it.
      	 */
      	@SuppressWarnings("unchecked")
      	@Override
      	public Object readFrom(Class<Object> type, Type genericType, Annotation[] annotations, MediaType mediaType,
      			MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException {
      		if(type.equals(Collection.class) && !(genericType instanceof ParameterizedType)) {
      			genericType = new ParameterizedCollectionType<Object>((Class)genericType);
      		}
      		return super.readFrom(type, genericType, annotations, mediaType, httpHeaders, entityStream);
      	}
      

      Attachments

        Activity

          People

            sergey_beryozkin Sergey Beryozkin
            dobes_vandermeer Dobes Vandermeer
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: