On 20/12/11 10:21, Brice wrote:
Le lundi 19 décembre 2011 à 23:41, Sergey Beryozkin a écrit :
Hi Brice
On 19/12/11 20:28, Brice wrote:
Le lundi 19 décembre 2011 à 17:07, Brice a écrit :
Hi Sergey,
I had some time to work on these and I still have issues.
For the Language, finally it will be dealt with PathParam
/path/to/fr_FR/resource , however my LocaleParameterHandler is never called.
InjectionUtils.handleParameter actually look for the first matching constructor
accepting a string, regardless the provider has a ParameterHandler or not for
that type. I'm using 2.3.3.
For that it seems there is no real solution, and Locale is not the only class
we have in this situation.
I read this
http://cxf.547215.n5.nabble.com/ParameterHandler-not-invoked-for-Date-parameter-td3322606.html
but it didn't help :/
That actually works now - because Date will throw an exception in case
of unrecognized formats and this is then handled by registered Parameter
handlers.
OK. However I meant (at time of writing) it didn't help for objects in general
with a single String argument constructor that don't fail, and I don't want to
instantiate them through this constructor. Sorry I wasn't clear enough.
The current workaround is to have a CXFLocaleWrapper, that pretty much sucks,
but it works. I looked at the code of future versions of the InjectionUtils, it
doesn't seem to be fixed, yet I'm still a CXF neophyte.
Could it work with a custom RequestHandler, or an Interceptor right before the
actual invocation (thinking loudly) ?
I've been kind of reluctant to get ParameterHandlers getting in front of
the default parameter class instantiation algorithm. May be it's not a
big deal but I was just too overcautious may be.
The case with the Date class was probably the only real problem which
has now been fixed.
We have a case number 2 now which is really to do with the Locale single
constructor bug. I think I may just do 'if (Locale)' check and start
considering checking ParameterHandlers first once/if we have a case
number 3 :-), we'll do something.
If you don't want to break things which I totally understand, You might
introduce some annotation reading, like @OverrideConstructor.
Or some way to specify the instanciatiuon strategy for the type.
For now I've added a Locale check;
I'm wondering if you can just use String parameter as an alternative and
check for '_' in meantime ?
I'm not sure to follow you there. Do you mean wrinting code like this :
@GET
@Path("{locale}/doit")
Response doSomethingWithLocale(@PathParam("locale") String locale);
I'm not sure I proceed like that, because I would also like to perform some
generic verification/validation on the parameters (usually the most common
parameters), but maybe ParameterHandlers are not really made for that.
How would do add a layer of validation before the actual call. I was thinking
to add an interceptor after the JAXRSInInterceptor.
I guess ParameterHandlers can do the validation on its own, but IMHO a
filter will do much better, say get UriInfo injected into RequestHandler
filter and check all the path and query parameters, etc.
ParameterBeans (those annotated with PathParam("") etc) can do the
validation.
JAX-RS 2.0 will require some support for the bean validation, it will be
very annotation-centric, so, but that will be another option
Also for the ExceptionMapper, I cannot access the OperationResourceInfo, the code
"messageContext.getContextualProperty(OperationResourceInfo.class)" actually returns
"null" at that time. In the stackframe the code is executing from
JAXRSUtils.convertFaultToResponse() line 1170.
Investigating the injected MessageContext, I have found one place where
OperationResouceInfo, but it's clearly not future proof
So injection looks like that
@Context private MessageContext messageContext;
And I fetch the OperationResourcveInfo this way :
OperationResourceInfoStack operationResourceInfoStack =
(OperationResourceInfoStack)
messageContext.getContextualProperty("org.apache.cxf.jaxrs.model.OperationResourceInfoStack");
OperationResourceInfo ori = (OperationResourceInfo)
operationResourceInfoStack.peek().getMethodInfo();
peeking in a stack is a bit scabrous in my opinion.
Instead I wrote a RequestHandler that actually fetch the information from the
message itself and store this information in an injected MessageContext :
OperationResourceInfo operationResourceInfo =
message.getExchange().get(OperationResourceInfo.class);
SupplementaryInfo si =
operationResourceInfo.getAnnotatedMethod().getAnnotation(SupplementaryInfo.class);
messageContext.put(BusinessServiceXFConstants.SERVICE_NAME, si.value());
And I can retrieve these values with more confidence in the ExceptionMapper.
It does seem safe also as it's only contextual to the message; is it possible
to confirm that point ?
This approach looks good; I'm not sure yet why
messageContext.getContextualProperty(OperationResourceInfo.class) does
not work; well - I just checked, message.getContextualProperty expects
a String parameter so OperationResourceInfo.class.toString() is used as
a key but OperationResourceInfo.class is used as a key as is when saving.
The above approach looks OK, or use
PhaseInterceptorChain.getCurrentMessage().getExchange().get(OperationResourceInfo.class);
I've fixed
messageContext.getContextualProperty(OperationResourceInfo.class) too
Ok, cool this looks even better.
On yet another topic, and just to confirm as it seems to be ok: do ExceptionMappers are
ordered from the most specific exception to the most generic? For example I have some
business exceptions, some known technical exceptions, but I'd like to catch also all
"undeclared" throwables, so any added ExceptionMapper belately won't affect the
fact that a ThrowableMapper will be used only if no other ExceptionMapper matches?
Yes - if it does not work as expected in the current CXF you work with
then please upgrade - it has to work
Sergey
Regards,
Brice
Cheers, Sergey
Anyway thanks for your ideas and suggestions.
--
Brice
Le vendredi 16 décembre 2011 à 11:00, Sergey Beryozkin a écrit :
Hi Brice
On 15/12/11 20:04, Brice wrote:
Hi Sergey,
I think I hit another issue. I think I got a workaround, yet I'm not sure it is
the best way to do this. But first I'll explain the faced problem :
I would like to map some exception that might be raised during the message
handling, some raised by the invoker; so an ExceptionMapper could fit in with
some elegance.
However, in my Response I would like to get some "technical" data that will
most probably located on an annotation aside the other JAXRS annotations (@GET, @Path,
etc.).
But the signature is "Response toResponse(Exception)", so I don't have any
information on the targeted object.
You can get CXF-specific MessageContext injected in that mapper and use
messageContext.getContextualProperty(OperationResourceInfo.class); and
OperationResourceInfo.getAnnotatedMethod will return Method with the
annotations, you can get to the class-level annotations from there too
if needed
Also I don't have a Response for this exxcpetion when an exception occur in
"JAXRSInInterceptor.handelMessage(Message)" then I might loose all the proxies
information (thread local is cleared).
JAXRSInInterceptor checks ExceptionMappers if the exception is thrown
during handleMessage(Message)
So the workaround would be to also have a RequestHandler :
- the "ExceptionMapper" will create a Response with an incomplete entity
- the "RequestHandler" in the "handleResponse(Message, OperationResourceInfo, Response)" might be
able create a new Response from the original and to "enhance" the entity with the information from the
annotations. The annotation will be accessed through :
"message.getExchange().get(OperationResourceInfo.class).getMethodToInvoke().getAnnotation(SomeCustomAnnotation.class)".
In my opinion this approach looks a wrong, but yet again it is a neophyte
workaround.
This is possible, why not, but hope the above hint re
OperationResourceInfo can make it a bit simpler
Cheers, Sergey
What do you think ? Would it be possible to achieve a better and simpler
solution than having to split this logic ?
Thanks again for your time and consideration :)
--
Brice
--
Sergey Beryozkin
Talend Community Coders
http://coders.talend.com/
Blog: http://sberyozkin.blogspot.com
--
Brice