I'll add the code at the end of this email.
So far what looks to work best is to have a provider that only handles
cases where I have a class that impements MultivaluedMap and leave
those cases where MultivaluedMap it's self is used to
FormEncodingReaderProvider to handle.
Right now the values that get passed into the MultivaluedMap from the
html form are url encoded. A value of "This is a test" is encoded as
"This+is+a+test", for example. I plan to add a helper to decode these.
Also I want to add a helper to strip out cross site scripting attach
strings from incoming form data. The last case I'm thinking about is
putting validation helpers here.
Here is the code:
package org.sherpa.jaxrs;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.Provider;
@Consumes("application/x-www-form-urlencoded")
@Provider
public class XxxSherpaFormEncodingReader implements MessageBodyReader<Object> {
public boolean isReadable(Class<?> clazz, Type genericType,
Annotation[] annotations, MediaType mt) {
return !clazz.isInterface() &&
MultivaluedMap.class.isAssignableFrom(clazz);
}
public MultivaluedMap<String, String> readFrom(Class<Object> clazz,
Type genericType, Annotation[] annotations, MediaType
type,
MultivaluedMap<String, String> headers, InputStream is)
throws IOException {
try {
String charset = "UTF-8";
ByteArrayOutputStream bos = new ByteArrayOutputStream();
copy(is, bos, 1024);
String postBody = new String(bos.toByteArray(), charset);
MultivaluedMap<String, String> params =
makeResult(clazz);
readParams(postBody, (MultivaluedMap<String, String>)
params);
return params;
} catch (Exception e) {
throw new WebApplicationException(e);
}
}
@SuppressWarnings("unchecked")
public MultivaluedMap<String, String> makeResult(Class<Object> clazz)
throws InstantiationException, IllegalAccessException{
return (MultivaluedMap<String, String>) clazz.newInstance();
}
public static void copy(final InputStream input, final OutputStream
output,
final int bufferSize) throws IOException {
final byte[] buffer = new byte[bufferSize];
int n = 0;
n = input.read(buffer);
while (-1 != n) {
output.write(buffer, 0, n);
n = input.read(buffer);
}
}
protected static void readParams(String body,
MultivaluedMap<String, String> params) {
if((body != null) && (body.length() != 0)){
List<String> parts = Arrays.asList(body.split("&"));
for (String part : parts) {
String[] keyValue = part.split("=");
// Change to add blank string if key but not
value is specified
if (keyValue.length == 2) {
params.add(keyValue[0], keyValue[1]);
} else {
params.add(keyValue[0], "");
}
}
}
}
}
On Thu, Nov 20, 2008 at 3:06 AM, Sergey Beryozkin
<[EMAIL PROTECTED]> wrote:
Hi Tom
Rather than modify FormEncodingReaderProvider I made my own provider
that handles classes that implement MultivalueMap.
On the plus side
there is no need to modify FormEncodingReaderProvider and I can use
this provider in other jaxrs implementations.
On the negative side I had to duplicate some of the code in
FormEncodingReaderProvider
(which I just copied from it. thank you vary much!). I have included
my new provider. You are welcome to use it any way you wish, but be
warned that I have not tested it yet.
The provider has not been included with this email, but I'd be interested in
looking at the code
you did to handle cases where specific MultivaluedMap implementations are
listed in signatures and possibly applying it to FormEncodingReaderProvider.
So if you could post it then it would be helpful
Out of curiosity - why having a default provider impl (say be it a CXF JAXRS
one or a Jersey one) is not always sufficient for your case ? Do you have
some optimized MultivaluedMap impls ?
Or some additional helper methods ? In this case it might make sense to
update FormEncodingReaderProvider
Thanks, Sergey
On Wed, Nov 19, 2008 at 10:40 AM, Tom McGee <[EMAIL PROTECTED]>
wrote:
You may want to wait on that patch. I'm playing with it and have
already found a problem. If you have a class in your signature that
implements MultivaluedMap you get an exception thrown. If you want
only the option of using MultivaluedMap in the signature then leave
FormEncodingReaderProvider unchange. If you want to allow a class that
implements MultivaluedMap in the method signature then stay tuned ...
I'm working on it.
On Wed, Nov 19, 2008 at 9:47 AM, Sergey Beryozkin
<[EMAIL PROTECTED]> wrote:
Yea, agreed - but if are you using MultivaluedMap in your signature then
it
should work fine.
BradO - if you're reading it - it's a perfect time for a patch :-),
unless
Tom does it first :-)
Thanks, Sergey
----- Original Message ----- From: "Tom McGee"
<[EMAIL PROTECTED]>
To: <[email protected]>
Sent: Wednesday, November 19, 2008 5:37 PM
Subject: problem in FormEncodingReaderProvider or in my java knowledge
Line 47 of org.apache.cxf.jaxrs.provider. FormEncodingReaderProvider
reads:
return type.isAssignableFrom(MultivaluedMap.class);
I think maybe it should be:
return MultivaluedMap.class.isAssignableFrom(type);
Or maybe I'm just showing my ignorance :-).