I'm confused.
Can you post a sample resource class, a sample signature and a sample
adapter.
In short.
To be honest, I'm not sure more changes have to be applied. My understanding
was you had adapters converting from String to A.
This is not my use case, but is also possible by my previous fix.
Now it appears you need a
conversion from String to A and then from A to B. Why can't yo have adapters
converting from String to B ?
Because I use the adapters also for normal webservices. I dont want to
have extra String->Something adapters.
Here is my example, which I wanted to contribute to CXF, which simulates
a "old" webservice by REST calls, and which require my desired behavior
of XMLAdapters concerning REST. Would be nice if you include this in trunk.
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethodBase;
import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
import org.apache.commons.httpclient.methods.DeleteMethod;
import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.cxf.helpers.IOUtils;
import org.apache.cxf.jaxrs.impl.MetadataMap;
import org.apache.cxf.jaxrs.impl.UriBuilderImpl;
import org.apache.cxf.jaxrs.provider.JAXBElementProvider;
import org.apache.cxf.jaxrs.provider.JSONProvider;
import org.apache.cxf.jaxrs.utils.AnnotationUtils;
import org.apache.cxf.jaxrs.utils.JAXBUtils;
/**
* Invokes REST operations for a given SEI interface. This assumes that
the SEI
* interface is exposed as REST service (ideally, the REST service bean
* implements the SEI interface). The SEI interface may be additionally
exposed
* as non-REST webservice, in which case a webservice port can be passed as
* first parameter to newInstance(), so that the webservice methods are
called
* in cases where the called SEI method is not annotated with
@GET/@PUT/... .
*/
public class RESTbyContract implements java.lang.reflect.InvocationHandler {
HttpClient httpclient = new HttpClient();
private MessageBodyReader reader;
private MessageBodyWriter writer;
private final Object obj;
private final MediaType mtWrite;
private final MediaType mtRead;
private final URI baseURI;
/**
* @param <T>
* @param obj
* SEI interface instance, may be <code>null</code>
* @param c
* SEI interface
* @param mtWrite
* media type to write a message body request
* @param mtRead
* desired media type to read a message body response
* @param baseURI
* the base URI of the REST service
* @return
*/
public static <T> T newInstance(T obj, Class<T> c, MediaType mtWrite,
MediaType mtRead, URI baseURI) {
return (T)
java.lang.reflect.Proxy.newProxyInstance(c.getClassLoader(), new Class[]
{ c }, new RESTbyContract(obj, mtWrite, mtRead, baseURI));
}
private RESTbyContract(Object obj, MediaType mtWrite, MediaType mtRead,
URI baseURI) {
this.obj = obj;
this.mtWrite = mtWrite;
this.mtRead = mtRead;
this.baseURI = baseURI;
}
public Object invoke(Object proxy, Method m, Object[] args) throws
Throwable {
try {
Annotation[] annotations = m.getAnnotations();
HttpMethodBase method;
if (AnnotationUtils.getAnnotation(annotations,
POST.class) != null) {
method = new PostMethod();
} else if (AnnotationUtils.getAnnotation(annotations, GET.class) !=
null) {
method = new GetMethod();
} else if (AnnotationUtils.getAnnotation(annotations, PUT.class) !=
null) {
method = new PutMethod("");
} else if (AnnotationUtils.getAnnotation(annotations, DELETE.class)
!= null) {
method = new DeleteMethod();
} else {
Object result = m.invoke(obj, args);
// return an empty list instead of null if a
list is expected
if (result == null && m.getReturnType() ==
List.class)
result = new ArrayList();
return result;
}
ByteArrayOutputStream requestBody = null;
UriBuilderImpl b = new UriBuilderImpl(baseURI);
b.path(m.getDeclaringClass());
b.path(m);
Map<String, Object> values = new HashMap<String,
Object>();
int i = 0;
if (args != null)
for (Object arg : args) {
Annotation[] annos =
m.getParameterAnnotations()[i];
PathParam path =
AnnotationUtils.getAnnotation(annos, PathParam.class);
if (path != null) {
arg = JAXBUtils.useAdapter(arg,
AnnotationUtils.getAnnotation(annos, XmlJavaTypeAdapter.class), true);
values.put(path.value(), arg);
} else if (requestBody != null) {
throw new RuntimeException("body
already defined!");
} else {
if (writer == null) {
if
("application/xml".equals(mtWrite.toString())) {
writer = new
JAXBElementProvider();
} else {
writer = new
JSONProvider();
}
}
requestBody = new
ByteArrayOutputStream();
writer.writeTo(arg, arg.getClass(), arg.getClass(), annos,
mtWrite, new MetadataMap<String, Object>(), requestBody);
}
i++;
}
URI restUri = b.buildFromMap(values);
method.setURI(new
org.apache.commons.httpclient.URI(restUri.toString(), true));
method.addRequestHeader("Accept", mtRead.toString());
if (requestBody != null) {
RequestEntity entity = new
ByteArrayRequestEntity(requestBody.toByteArray());
((EntityEnclosingMethod)
method).setRequestEntity(entity);
method.addRequestHeader("Content-Type",
mtWrite.toString());
}
int responseCode = httpclient.executeMethod(method);
if (responseCode != 200 && responseCode != 204) {
throw new RuntimeException(method.getStatusText() + "\n" +
method.getResponseBodyAsString());
}
Class targetType = m.getReturnType();
if (targetType == Void.TYPE) {
return null;
}
InputStream responseBody =
method.getResponseBodyAsStream();
if (reader == null) {
if
("application/xml".equals(mtRead.toString())) {
reader = new JAXBElementProvider();
} else {
reader = new JSONProvider();
}
}
if (targetType.isPrimitive())
return
targetType.getConstructor(String.class).newInstance(IOUtils.toString(responseBody));
if (targetType == String.class)
return IOUtils.toString(responseBody);
Type genericType = m.getGenericReturnType();
Object result = reader.readFrom(targetType, genericType, annotations,
mtRead, new MetadataMap<String, String>(), responseBody);
return result;
} catch (InvocationTargetException e) {
throw e.getTargetException();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("unexpected invocation exception: " +
e.getMessage());
}
}
}