Hi Sergey, you suggested me the solution to use ParameterHandler, this
would work I think, however I want to reuse my existing XMLAdapters, I
have hundreds of them in my project, and dont want to create hundreds of
new ParameterHandlers (actually I not counted them, they get generated).
So a fix for the problem which works in my test cases is the following:
if (!InjectionUtils.isSupportedCollectionOrArray(parameterClass) &&
parameterClass == parameterType) {
parameterClass = getActualType(parameterClass, parameterType,
parameterAnns);
if (parameterType != parameterClass) {
// case a XmlAdapter is available
parameterType = parameterClass;
Object response = createHttpParameterValue(parameter,
parameterClass, parameterType, message, values, ori);
response = checkAdapter(response, parameterClass, parameterAnns,
false);
return response;
}
}
This must be inserted in class JAXRSUtils here:
private static Object processParameter(Class<?> parameterClass,
Type parameterType,
Annotation[] parameterAnns,
Parameter parameter,
MultivaluedMap<String,
String> values,
Message message,
OperationResourceInfo ori) {
.... else {
//HERE
return createHttpParameterValue(parameter,
parameterClass,
parameterType,
message,
values,
ori);
}
}
Also I copied the three methods checkAdapter/getActualType/getAdapter
from AbstractJAXBProvider into JAXRSUtils without any change except for
making them static since they are now called from a static method, so
they should be better kept in a general utility class.
So actually what the code does, it just marshalling the parameter type
before calling createHttpParameterValue and finally unmarshalling the
result of createHttpParameterValue, accordingly to the
XmlJavaTypeAdatper found in the annotations of the parameter. It works
the same way e.g. JAXBElementProvider converts the type before / result
after reading the message body, however I am only interested in the case
that we are not dealing with a collection or a special generic type, for
which I dont see a usecase currently.
With this fix, I also want to handle the problem of transmitting e.g. an
Integer over the network using SOAP or JSON, by defining the Integer to
be the BoundType and a IntegerWrapper class to be the ValueType and a
corresponding XmlAdapter converting between those, and by just using the
annotation @XmlJavaTypeAdatper(IntegerAdapter.class) with a
Integer-typed parameter. Thus I can easily transmit a Integer over the
network - or with our previous fix a List of Integer. Of course
IntegerWrapper would be a custom bean class of mine, but maybe CXF could
include such classes and corresponding adapters for all primitive types
and String.
Imagine following annotated parameter:
void methodA(@PathParam("id") @XmlJavaTypeAdapter(XoverY.class) X x) {
doSomethingWith(x);
}
The expected semantics is that class Y is instantiated by e.g.
Y.valueOf(id), then the XmlJavaTypeAdapter converts it to an instance of X.
However the current implementation looks for a valueOf() method in class X
and not class Y, it just not takes the XmlJavaTypeAdapter annotation into
account. So I actually end up with a not very elegant workaround:
void methodA(@PathParam("id") Y y) {
X x = new XoverY().unmarshal(y);
doSomethingWith(x);
}
I require this glue code in most of my REST methods, so the code looks not
so nice as it could look, but nevertheless I consider it as a bug.
I consider it to be a restriction :-).
Currently you have two options with converting path vars into beans:
1.
void methodA(@PathParam("") Xover x) {
}
all the captured Path variables will be injected into Xover, example, if we
have a path variable 'id' then a Xover.setId method will be invoked.
2. Register a ParameterHandler (as a jaxrs:provider), ex,
XoverParameterHandler<Xover>
Hope it helps
Cheers, Sergey