I'm trying to invoke a bean in an interceptor and bind some parameters using the annotations but when the method is invoked it seems like the annotations are ignored and instead the body is bound to the first parameter and the second parameter is null.
I've tried the same XPath using the Blueprint DSL and it works fine so I'm sure this isn't the issue. My method is something like this: -
public void intercept(
#XPath(value = "//custom:myElement/text()",
namespaces = { #NamespacePrefix(prefix = "custom", uri = "http://my.website.com/custom") },
resultType = String.class) String elementValue,
#Body String body) {
LOG.info("elementValue {}", elementValue);
LOG.info("body {}", body);
}
And my interceptor is something like this.
<camel:interceptSendToEndpoint uri="direct:core-service">
<camel:to uri="bean:interceptor?method=intercept" />
</camel:interceptSendToEndpoint>
When the interceptor is invoked I get a full soap envelope printed for the first log statement and null for the other.
Do I need to do anything to make this bean annotation aware? From the documentation it seems like I just need to add the annotations as above. I can't believe it just doesn't work.
This is running in JBose Fuse so it's camel 2.10 if that makes a difference.
Update
I've tried removing the interceptor from the question and just performing in a simple route and it still doesn't work. Do I need to type cast the incoming String as XML somehow or does it need to be a JAXB entity in the body for #XPath to work?
There was a a bug in Camel that caused #XPath on bean parameters to not work when using OSGi blueprint AFAIR.
Its fixed in recent Camel released and also in patches for JBoss Fuse available in the customer portal.
As a workaround you can always do the xpath in the bean yourself.
Related
I need to retrieve the path param map in my spring boot application and I noticed that the following line of code:
final Map<String, String> pathVariables = (Map<String, String>) request
.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
only works when in a spring boot InterceptorHandler class, I guess because the "path param" abstraction is spring's.
Problem is that I'm using spring security, defining my own filter chain:
http.addFilterBefore(...).addFilterAfter(myFilterNeedingPathParam) //series of filters
And the last filter needs the path params map. My idea would be to put the interceptor before or, if you want, make sure that the last filter is executed after.
Is there a way to do so?
When in the Spring InterceptorHandler, check the actual class of the request, you may need to cast your request to that. Also look into the source code for that class and see if it's pulling that value from a ThreadLocal of some sort.
Autowired FluentProducerTemplate in a service bean will intermittently have a header set from a previous call in another method in the same service bean. I set the CamelOlingo4.keyPredicate is the header in this case.
FluentProducerTemplate producerTemplate;
UserAccount account = producerTemplate
.withHeader("CamelOlingo4.$select", "cva_useraccountid,statuscode,emailaddress,cva_firstname,cva_lastname,cva_password,cva_lastlogout,cva_lastlogin,cva_lastloginattempt,cva_lockeduntil,cva_loginattemptcount,_cva_contact_value")
.withHeader("email",username)
.withHeader("activeStatus",MSDynamicsAccountStatusCodes.ACTIVE.toString())
.withHeader("lockedStatus",MSDynamicsAccountStatusCodes.LOCKED.toString())
.to("direct:login")
.request(UserAccount.class);
And my route definition:
from("direct:login")
.id("routes.id.login")
.toD("olingo4://read/{{route.login}}?$filter=emailaddress eq '${header.email}' and (statuscode eq ${header.activeStatus} or statuscode eq ${header.lockedStatus})").log("Response from Olingo: ${body}")
.process(new OlingoProcessor());
I do fire an async request route with the keyPredicate upon successful login...
producerTemplate
.withHeader("CamelOlingo4.keyPredicate", userId)
.withHeader("Content-Type", "application/json")
.withBody(user)
.to("direct:tracklogin")
.asyncSend();
And route defined for track:login:
from("direct:tracklogin")
.id("routes.id.track.login")
.marshal()
.json(JsonLibrary.Jackson)
.convertBodyTo(String.class)
.log("JSON Body: ${id} ${body}")
.to("olingo4://patch/{{route.patch.track-login}}");
Random times, the "direct:login" route will have the keyPredicate set in the header, causing an error in my OlingoProcessor, since I'mn not getting the expected object back from the exchange body. (Olingo Object is different when querying with a keyPredicate)
Not sure if the issue lies with my implementation, the camel-olingo4 comp or the FluentProducerTemplate itself... But I do see there is a clearAll() method on the FluentProducerTemplate. I'm suspecting i need to call it whenever i use the autowired producer template within the same service bean. Just need some confirmation...
As Spring default scope is singleton, indeed the injected producer template bean instance will be reused, and the clearAll() should be called before setting headers, body, etc...
Of course, another possible solution would be to create each time a brand new producer template instance:
FluentProducerTemplate producerTemplate = context.createFluentProducerTemplate();
UserAccount account = producerTemplate.withHeader(...)
TL;DR
Does an autowired FluentProducerTemplate need to have its headers and body cleared before use within same service?
In Camel 2, yes. In Camel 3, no.
Long Story
The CamelAutoConfiguration from Camel's Spring Boot Starter create a FluentProducerTemplate with no specific scope, hence Spring's default scope singleton is applied and you have only one instance per application.
The FluentProducerTemplate is thread-safe. In Camel 2, thread-safety is achieved by storing the message body and headers in ThreadLocals. If you don't clear the headers after/before usage you may occasionally see left-overs from previous invocations. So, yes, you'd have to call clearHeader() or clearAll() manually.
The situation in Camel 3 is a bit more relaxed. There, thread-safety is achieved by producing new instances of FluentProducerTemplate whenever you call a method that would otherwise modify the template (headers, body). Clearing the values is not strictly necessary anymore as far as I can tell.
I'm using the Jersey implementation for JAX-RS, and I was looking for an example where I can use the Bean Validation in POST requisitions. I have this operation, for example:
#POST
#Path("document/annotations/save")
#Produces("application/json")
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Map<String, Object> saveAnnotation(
#FormParam("user") String userStr,
#FormParam("documentId") String documentId,
#FormParam("documentPage") Integer documentPage,
#FormParam("annotationContent") String annotationContent,
#FormParam("annotationId") Long annotationId,
#FormParam("isMobile") Boolean isMobile) { // the code... }
I wanna use validations constraints (#NotNull, #Pattern, etc) for each method param. I saw this doc where they're using the Seam Framework to do that.
Currently, I'm trying to use the javax.validation implementation to validate my requests, but it doesn't working.
Is there a way to use the JSR-303 specification with JAX-RS?
Tnks.
This is currently not possible using Jersey; one possible alternative is to write a customer resource filter and bind to the #NotNull, etc. annotations.
It would be simpler if it was encapsulated in a resource class because you could then bind to a #Valid annotation on your method and validate the bean in one shot.
Because JSR-303 is designed to deal with beans and not a collection of parameters then it ends up being very verbose when you try to bend it to your will.
IMHO it's better not to keep validation inside your class anyway and to either use the pipes and filters pattern, i.e. ContainerRequestFilter, or to use something like AspectJ as #Willy suggested.
It's possible. See docs for latest Jersey
https://jersey.java.net/documentation/latest/bean-validation.html#d0e9380
https://jersey.java.net/documentation/latest/bean-validation.html
Posted in spring forum with no response.
I have the following code snippet (from here), which is part of my pet project.
#Controller
#RequestMapping("/browse")
public class MediaBrowser {
...
#RequestMapping("/**")
public final ModelAndView listContents(final HttpServletRequest request) {
String folder = (String) request.getAttribute(
HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
...
}
I access the following url:
http://localhost:8080/myapp/browse
In spring 3.0.6.RELEASE, I got the folder variable as null, which is the expected value.
In spring 3.1.RC1, the folder variable is /browse.
Is this a bug or has something changed in spring-3.1?
As skaffman said, you probably shouldn't use PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE. Take a look at How to match a Spring #RequestMapping having a #pathVariable containing "/"? for an example of using AntPathMatcher to accomplish what you are trying
This looks very much like an internal implementation detail of the framework, one that you should not be relying on.
The javadoc for PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE says:
Note: This attribute is not required to be supported by all HandlerMapping implementations. URL-based HandlerMappings will typically support it, but handlers should not necessarily expect this request attribute to be present in all scenarios.
I wouldn't be surprised if the behaviour changed slightly between 3.0 and 3.1.
Is there a way to use Spring lookup method inject with parameters? For example, I want to be able to instantiate prototype-scoped beans while passing them arbitrary parameters via constructor.
It looks like this vital feature was finally added in Spring 4.1.0.RC2. I have tested it and it seems to work.
It was added as part of JIRA ticket SPR-7431 ("Passing lookup-method arguments to created bean constructor"):
<lookup-method/> should allow specifying any number of parameters. These parameters should be passed directly to the constructor of the newly created bean.
For more info on how the feature was finally added, this blog post was written by the guy who opened the JIRA ticket.
You can inject them via field/setter injection. (Note that constructor injection is frowned upon by spring, although it's supported)
in short, no. Spring does support something called "method injection" but it's different than you're thinking. Spring also supports constructor injection, but then you're not calling the constructor yourself, Spring is, and wiring it itself.
Instead, you can use reflection to instantiate the class and pass arbitrary parameters yourself:
Class<MyObject> clazz = MyObject.class; // this can be looked up or stored in a field, etc.
MyObject myObject = clazz.getConstructor(String.class, int.class)
.newInstance("arbitrary parameter", 42);