users@jersey.java.net

Re: [Jersey] Plugging in any String-based reading for _at_*Param <was> Re: [Jersey] Jersey Client: How can I POST an object? I'm getting an HTTP 415 error.

From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
Date: Fri, 20 Feb 2009 13:57:38 +0100

On Feb 19, 2009, at 6:46 PM, Paul Sandoz wrote:

> Hi,
>
> This email thread got me thinking that we should be able to support
> a general plugable solution similar to the message body reader
> approach.
>
> So.. i just committed to the trunk the support for
> StringReaderProvider (see end of email).
>
> The support for the string constructors and valueOf rules are
> implemented using this approach.
>
> TODO add support for JAXB and java.util.Date (where the date format
> can be expressed as an annotation).
>

Done. For now i have implemented java.util.Date for HTTP-formated
dates, still need to add support for a date format annotation. I moved
the interfaces they are now in jersey-core as follows:

   com.sun.jersey.spi.StringReaderProvider
   com.sun.jersey.spi.StringReader
   com.sun.jersey.spi.StringReaderWorkers

Paul.

> Paul.
>
>
> /**
> * Read a string value and convert to a Java type.
> * <p>
> * A {_at_link StringReaderProvider} is responisble for providing an
> instance
> * of this interface.
> *
> * @param <T> the Java type to convert to.
> *
> * @author Paul.Sandoz_at_Sun.Com
> */
> public interface StringReader<T> {
>
> /**
> * Read a string value and convert to a Java type.
> *
> * @param value The string value.
> * @return the instance of the Java type.
> */
> T fromString(String value);
> }
>
> /**
> * Contract for a provider that supports the conversion of a string
> to a
> * Java type. To add a <code>StringReaderProvider</code>
> implementation,
> * annotate the implementation class with <code>Provider</code>.
> * <p>
> * Such providers will be used when converting a String value to a
> java type
> * annotated by the *Param annotations such as {_at_link
> javax.ws.rs.QueryParam}.
> *
> * @param <T> The Java type.
> * @see javax.ws.rs.ext.Provider
> * @see com.sun.jersey.server.spi.StringReaderWorkers
> * @author Paul.Sandoz_at_Sun.Com
> */
> public interface StringReaderProvider<T> {
>
> /**
> * Obtain a StringReader that can produce an instance of a
> particular type
> * from a string.
> *
> * @param type the class of object to be produced.
> *
> * @param genericType the type of object to be produced. E.g. if
> the
> * string is to be converted into a method parameter, this will be
> * the formal type of the method parameter as returned by
> * <code>Class.getGenericParameterTypes</code>.
> *
> * @param annotations an array of the annotations on the
> declaration of the
> * artifact that will be initialized with the produced instance.
> E.g. if the
> * string is to be converted into a method parameter, this will be
> * the annotations on that parameter returned by
> * <code>Class.getParameterAnnotations</code>.
> *
> * @return the string reader, otherwise null.
> */
> StringReader<T> getStringReader(Class<?> type, Type genericType,
> Annotation annotations[]);
> }
>
> Paul.
>
> On Feb 16, 2009, at 4:17 PM, Paul Sandoz wrote:
>
>>
>> On Feb 13, 2009, at 11:52 PM, JavaGeek_Boston wrote:
>>
>>>
>>> Hello All,
>>> This is probably a remedial question, but I can't get my object to
>>> POST? I
>>> can return my entity via a @GET call, but I can't seem to post it
>>> as a form
>>> param. When I execute my POST, I get either an HTTP 415 or 400
>>> error,
>>> depending on what I set for @Consumes
>>>
>>> My object is a bean
>>> @XmlRootElement
>>> public class MyDocumentType implements Serializable{
>>> //some fields and getters and setters.
>>> }
>>>
>>> Here's my service:
>>> @POST
>>> @Path(DOC)
>>> @Consumes("application/xml")
>>> public String updateDocument(@HeaderParam(SESSION_ID_HEADER_KEY)
>>> String
>>> sessionId,
>>> @FormParam(DOC_OBJ) MyDocumentType doc) {
>>> confirmSessionIsValidAndAuthorIsLoggedIn(sessionId, doc);
>>> storeService.updateDocument(doc);
>>> return "SUCCESS: " + doc.getId();
>>> }
>>>
>>> Here's my client:
>>> Client client = new Client();
>>> resource = client.resource(serverURL);
>>> final WebResource finalPath = resource.path(path);
>>> Form form = new Form();
>>> form.add("doc", doc);
>>> return finalPath.type("application/
>>> xml").header(SESSION_ID_HEADER_KEY,
>>> sessionId).post(String.class, form);
>>>
>>>
>>> I get an HTTP 400 with that combination.
>>>
>>
>> The problem is that you are first using the media type "application/
>> xml" (Jersey should not allow this or should warn you).
>>
>> Second, you seem to want to add an XML document as a form parameter
>> value. It is only possible to support the same rules as for say
>> @QueryParam. See the following for more details on the rules:
>>
>> http://wikis.sun.com/display/Jersey/Overview+of+JAX-RS+1.0+Features#OverviewofJAX-RS1.0Features-ExtractingRequestParameters
>>
>>
>>> I think my bean is OK as I can retrieve a MyDocumentType via @GET.
>>>
>>> When I call:
>>> return
>>> finalPath
>>> .type
>>> (MediaType
>>> .APPLICATION_FORM_URLENCODED).header(SESSION_ID_HEADER_KEY,
>>> sessionId).post(String.class, form);
>>> with
>>> @Consumes("application/x-www-form-urlencoded")
>>> on the service, I get:
>>> SEVERE: A message body reader for Java type, class MyDocumentType,
>>> and MIME
>>> media type, application/x-www-form-urlencoded, was not found
>>>
>>
>> Are you sure you had the @FormParam present in such a case? If you
>> did not then i can reproduce what you observe.
>>
>>
>>>
>>> Is there something I'm missing? Any help would be greatly
>>> appreciated:
>>>
>>
>> If you only ever need to POST the XML document then you do not need
>> to use a form:
>>
>> @Consumes("multipart/form-param")
>> @POST
>> public String updateDocument(
>> @HeaderParam(SESSION_ID_HEADER_KEY) String sessionId,
>> DocumentType doc) { ... }
>>
>>
>> If you do want to POST the XML document and some other values as
>> well i recommend you utilize the "multipart/form-data" media type.
>> When using this type you can reuse all the supported message body
>> readers like those for JAXB:
>>
>> @Consumes("multipart/form-param")
>> @POST
>> public String updateDocument(
>> @HeaderParam(SESSION_ID_HEADER_KEY) String sessionId,
>> @FormParam(DOC_OBJ) MyDocumentType doc) { ... }
>>
>>
>> The reason for this difference is that the media type "application/
>> x-www-form-urlencoded" defines parameters in terms of strings and
>> there is no content-type associated with each parameter, thus the
>> general message body readers/writers cannot, like those for JAXB,
>> be utilized in such cases. Now, arguably we could improve JAX-RS to
>> work well with JAXB in such cases.
>>
>> When using "multipart/form-param" the parameters are encoded as
>> bytes and are associated with a content type thus we can reuse all
>> the message body reader functionality, such as that for JAXB.
>>
>> Hope that helps,
>> Paul.
>>
>>> Thanks,
>>> Steven
>>> Harvard Children's Hospital Informatics Program
>>> --
>>> View this message in context: http://n2.nabble.com/Jersey-Client%3A--How-can-I-POST-an-object---I%27m-getting-an-HTTP-415-error.-tp2324279p2324279.html
>>> Sent from the Jersey mailing list archive at Nabble.com.
>>>
>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>>
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>