The framework uses an ArgumentResolverService to build the arguments for the method listener execution. The default core implementation, the DelegatingArgumentResolverService, uses ArgumentResolvers under the hood to resolve each type of argument.
You can define your own ArgumentResolverand include it in your ArgumentResolverService to extend what type of paramters you can consume.
new DelegatingArgumentResolverService(ImmutableSet.of(
new MessageIdArgumentResolver(),
...
new MyCustomArgumentResolver()
));
There is a deeply nested payload in the SQS message, and it is desirable to only provide the field that is needed instead of passing the entire
message body into the method. For example, using the sample SQS Message below, only the user's group is necessary and therefore a custom
ArgumentResolver can be included
to extract that field to any method parameter annotated with the @UserGroup
annotation.
example:
public void messageListener(@UserGroup final String userGroup) {
// process mesage here
}
{
"payload": {
"user": {
"group": "admin"
}
}
}
-
Create a new annotation that indicates that this user group should be extracted.
@Retention(value = RUNTIME) @Target(ElementType.PARAMETER) public @interface UserGroup { }
-
Create a new implementation of the ArgumentResolver interface that will be able to resolve these arguments with those annotations.
public class UserGroupArgumentResolver implements ArgumentResolver<String> { private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); @Override public boolean canResolveParameter(MethodParameter methodParameter) { // make sure only String parameters with the @UserGroup annotations are resolved using this return ( methodParameter.getParameter().getType().isAssignableFrom(String.class) && AnnotationUtils.findParameterAnnotation(methodParameter, UserGroup.class).isPresent() ); } @Override public String resolveArgumentForParameter(QueueProperties queueProperties, MethodParameter methodParameter, Message message) throws ArgumentResolutionException { try { // You could build an actual POJO instead of using this JsonNode final JsonNode node = objectMapper.readTree(message.body()); final JsonNode userGroupNode = node.at("/payload/user/group"); if (userGroupNode.isMissingNode()) { return null; } else { return userGroupNode.textValue(); } } catch (IOException e) { throw new ArgumentResolutionException("Error parsing payload", e); } } }
-
Create a method that will use this argument, for example something like:
public void messageListener(@UserGroup final String userGroup) { // Do something here }
-
Build your ArgumentResolverService with this ArgumentResolver.
new DelegatingArgumentResolverService(ImmutableSet.of( // other ArgumentResolvers here new UserGroupArgumentResolver() ));
The Spring Starter provides an easier way to integrate argument resolvers, see spring-how-to-add-custom-argument-resolver.md.