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


Reply via email to