By the way, I asked about getting Locale supported at the spec level
Sergey
On 20/12/11 12:33, Sergey Beryozkin wrote:
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
--
Sergey Beryozkin
Talend Community Coders
http://coders.talend.com/
Blog: http://sberyozkin.blogspot.com